Has something gone haywire? Let us know about it!

gameoflifemaniac
 Posts: 1096
 Joined: January 22nd, 2017, 11:17 am
 Location: There too
Post
by gameoflifemaniac » June 8th, 2020, 12:25 pm
This amateur pile of code behaves weirdly sometimes:
Code: Select all
#include <iostream>
#include <ctime>
#include <unistd.h>
#include <cstdlib>
using namespace std;
main()
{
int x,y;
cout << "Choose grid dimensions (x,y):";
cin >> x >> y;
int current[x][y];
int next[x][y];
int neighbors;
srand((int)time(0));
for (int i = 0; i < y; i++)
for (int j = 0; j < x; j++)
{
current[i][j]=(rand()%2);
}
while (true)
{
for (int a = 0; a++ < 2*x + 5;)
cout << "X";
cout << endl;
for (int i=0;i<y;i++)
{
cout << "XX ";
for (int j = 0;j < x; j++)
{
current[i][j] ? cout << " " : cout << " ";
neighbors = 0;
for (int k = 1; k < 2; k++)
{
for (int l = 1; l++ < 2;)
{
if (kl)
neighbors+=current[(i+l)%y][(j+k)%x];
}
}
if (current[i][j])
{
(neighbors == 2  neighbors == 3) ? next[i][j] = 1 : next[i][j] = 0;
}
else
{
neighbors == 3 ? next[i][j] = 1 : next[i][j] = 0;
}
}
cout << "XX";
cout << endl;
}
for (int a = 0; a++ < 2*x + 5;)
cout << "X";
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
current[i][j] = next[i][j];
}
}
sleep(0.5);
system("cls");
}
}
Sometimes it allows impossible still lives like the Z pentomino to live close to the edge. How can I fix it?
EDIT: Great. Now it went haywire completely.
I was so socially awkward in the past and it will haunt me for my entire life.

gameoflifemaniac
 Posts: 1096
 Joined: January 22nd, 2017, 11:17 am
 Location: There too
Post
by gameoflifemaniac » June 21st, 2020, 6:26 am
...
I was so socially awkward in the past and it will haunt me for my entire life.

rowett
 Moderator
 Posts: 2073
 Joined: January 31st, 2013, 2:34 am
 Location: UK

Contact:
Post
by rowett » June 27th, 2020, 11:20 am
The % operator is not doing what you expect. When the value is negative it won't wrap it around. 1 % 20 is not 19, it's 1.

bubblegum
 Posts: 181
 Joined: August 25th, 2019, 11:59 pm
 Location: click here to do nothing
Post
by bubblegum » June 30th, 2020, 1:29 am
rowett wrote: ↑June 27th, 2020, 11:20 am
The % operator is not doing what you expect. When the value is negative it won't wrap it around. 1 % 20 is not 19, it's 1.
Apparently it's not even consistent. Boo. Try this:
Code: Select all
int mod(int a, int b) {
int s {(a > 0)  (a < 0)};
a = ((s + 1) > 0) ? a : b + a;
return a % b;
}
(excuse the horrible mess of simplified code)

gameoflifemaniac
 Posts: 1096
 Joined: January 22nd, 2017, 11:17 am
 Location: There too
Post
by gameoflifemaniac » July 1st, 2020, 5:54 am
bubblegum wrote: ↑June 30th, 2020, 1:29 am
rowett wrote: ↑June 27th, 2020, 11:20 am
The % operator is not doing what you expect. When the value is negative it won't wrap it around. 1 % 20 is not 19, it's 1.
Apparently it's not even consistent. Boo. Try this:
Code: Select all
int mod(int a, int b) {
int s {(a > 0)  (a < 0)};
a = ((s + 1) > 0) ? a : b + a;
return a % b;
}
(excuse the horrible mess of simplified code)
Actually I found a simpler way to do that, but was too lazy to implement it.
Just add 20 (if the grid's x size is 20 for example) to the x/y coordinates of the neighbors and then mod it.
Code: Select all
#include <iostream>
#include <ctime>
#include <unistd.h>
#include <cstdlib>
using namespace std;
main()
{
int x,y;
cout << "Choose grid dimensions (x,y):";
cin >> x >> y;
int current[x][y];
int next[x][y];
int neighbors;
srand((int)time(0));
for (int i = 0; i < y; i++)
for (int j = 0; j < x; j++)
{
current[i][j]=(rand()%2);
}
while (true)
{
for (int a = 0; a++ < 2*x + 5;)
cout << "X";
cout << endl;
for (int i = 0; i++ < y;)
{
cout << "XX ";
for (int j = 0; j++ < x;)
{
current[i][j] ? cout << " 0" : cout << " ";
neighbors = 0;
for (int k = 1; k++ < 2;)
{
for (int l = 1; l++ < 2;)
{
if (kl)
neighbors+=current[(i+l+x)%x][(j+k+y)%y];
}
}
if (current[i][j])
{
(neighbors == 2  neighbors == 3) ? next[i][j] = 1 : next[i][j] = 0;
}
else
{
neighbors == 3 ? next[i][j] = 1 : next[i][j] = 0;
}
}
cout << "XX";
cout << endl;
}
for (int a = 0; a++ < 2*x + 5;)
cout << "X";
for (int i = 0; i < y; i++)
{
for (int j = 0; j < x; j++)
{
current[i][j] = next[i][j];
}
}
sleep(0.5);
system("cls");
}
}
But still something's not right, because it went haywire completely!
I was so socially awkward in the past and it will haunt me for my entire life.

chris_c
 Posts: 963
 Joined: June 28th, 2014, 7:15 am
Post
by chris_c » July 2nd, 2020, 6:19 pm
gameoflifemaniac wrote: ↑July 1st, 2020, 5:54 am
But still something's not right, because it went haywire completely!
You should investigate the behaviour of these for loops:
Code: Select all
for (int k = 1; k++ < 2;)
{
for (int l = 1; l++ < 2;)
{
if (kl)
neighbors+=current[(i+l+x)%x][(j+k+y)%y];
}
}
e.g. add something like:
Code: Select all
std::cout << k << " " << l << std::endl;
to the inner loop. I doubt the result is what you intended.

gameoflifemaniac
 Posts: 1096
 Joined: January 22nd, 2017, 11:17 am
 Location: There too
Post
by gameoflifemaniac » July 3rd, 2020, 3:38 pm
chris_c wrote: ↑July 2nd, 2020, 6:19 pm
gameoflifemaniac wrote: ↑July 1st, 2020, 5:54 am
But still something's not right, because it went haywire completely!
You should investigate the behaviour of these for loops:
Code: Select all
for (int k = 1; k++ < 2;)
{
for (int l = 1; l++ < 2;)
{
if (kl)
neighbors+=current[(i+l+x)%x][(j+k+y)%y];
}
}
e.g. add something like:
Code: Select all
std::cout << k << " " << l << std::endl;
to the inner loop. I doubt the result is what you intended.
I've fixed it. Kind of. It behaves more like CGoL but still allows for impossible stuff on the edges.
Code: Select all
#include <iostream>
#include <ctime>
#include <unistd.h>
#include <cstdlib>
using namespace std;
main()
{
int x,y;
cout << "Choose grid dimensions (x,y):";
cin >> x >> y;
int current[x][y];
int next[x][y];
int neighbors;
srand((int)time(0));
for (int i = 0; i < y; i++)
for (int j = 0; j < x; j++)
current[i][j]=(rand()%2);
while (true)
{
for (int a = 0; a++ < 2*x + 5;)
cout << "X";
cout << endl;
for (int i = 0; i++ < y;)
{
cout << "XX ";
for (int j = 0; j++ < x;)
{
current[i][j] ? cout << " 0" : cout << " ";
neighbors = 0;
for (int deltay = 1; deltay < 2; deltay++)
for (int deltax = 1; deltax < 2; deltax++)
if (deltaxdeltay)
neighbors+=current[(i+deltax+x)%x][(j+deltay+y)%y];
if (current[i][j])
(neighbors == 2  neighbors == 3) ? next[i][j] = 1 : next[i][j] = 0;
else
neighbors == 3 ? next[i][j] = 1 : next[i][j] = 0;
}
cout << "XX";
cout << endl;
}
for (int a = 0; a++ < 2*x + 5;)
cout << "X";
for (int i = 0; i++ < y;)
for (int j = 0; j++ < x;)
current[i][j] = next[i][j];
sleep(0.5);
system("cls");
}
}
Also how is:
Code: Select all
for (int deltax = 1; deltax++ < 2;)
any different from
Code: Select all
for (int deltax = 1; deltax < 2; deltax++)
?
I've reverted the 2nd version back and it worked correctly. How?
I was so socially awkward in the past and it will haunt me for my entire life.

chris_c
 Posts: 963
 Joined: June 28th, 2014, 7:15 am
Post
by chris_c » July 3rd, 2020, 4:15 pm
gameoflifemaniac wrote: ↑July 3rd, 2020, 3:38 pm
Also how is:
Code: Select all
for (int deltax = 1; deltax++ < 2;)
any different from
Code: Select all
for (int deltax = 1; deltax < 2; deltax++)
?
I've reverted the 2nd version back and it worked correctly. How?
As explained
here. The structure of a for loop in C++ is:
Code: Select all
for (initstatement; condition; iteration_expression)
The initstatement is always executed at the beginning.
The condition is evaluated
before every loop. If the condition is nonzero then loop executes, otherwise the for loop ends.
The iteration_expression is evaluated at the
end of every loop. (If the condition is 0 to begin with then the iteration_expression is never evaluated.)
Therefore in your original method the variable was being incremented before every loop but the second for is incrementing after every loop.
Off the top of my head I can't think any good examples where the condition statement would have a side effect such as incrementing a variable so I would avoid doing that kind of thing.

gameoflifemaniac
 Posts: 1096
 Joined: January 22nd, 2017, 11:17 am
 Location: There too
Post
by gameoflifemaniac » July 3rd, 2020, 4:20 pm
chris_c wrote: ↑July 3rd, 2020, 4:15 pm
gameoflifemaniac wrote: ↑July 3rd, 2020, 3:38 pm
Also how is:
Code: Select all
for (int deltax = 1; deltax++ < 2;)
any different from
Code: Select all
for (int deltax = 1; deltax < 2; deltax++)
?
I've reverted the 2nd version back and it worked correctly. How?
As explained
here. The structure of a for loop in C++ is:
Code: Select all
for (initstatement; condition; iteration_expression)
The initstatement is always executed at the beginning.
The condition is evaluated
before every loop. If the condition is nonzero then loop executes, otherwise the for loop ends.
The iteration_expression is evaluated at the
end of every loop. (If the condition is 0 to begin with then the iteration_expression is never evaluated.)
Therefore in your original method the variable was being incremented before every loop but the second for is incrementing after every loop.
Off the top of my head I can't think any good examples where the condition statement would have a side effect such as incrementing a variable so I would avoid doing that kind of thing.
Thanks for the explanation! But I still can't figure out how to make it work perfectly.
Code: Select all
#include <iostream>
#include <ctime>
#include <unistd.h>
#include <cstdlib>
using namespace std;
main()
{
int x,y;
cout << "Choose grid dimensions (x,y):";
cin >> x >> y;
int current[x][y];
int next[x][y];
int neighbors;
srand((int)time(0));
for (int i = 0; i < y; i++)
for (int j = 0; j < x; j++)
current[i][j]=(rand()%2);
while (true)
{
for (int a = 0; a < 2*x + 5; a++)
cout << "X";
cout << endl;
for (int i = 0; i < y; i++)
{
cout << "XX";
for (int j = 0; j < x; j++)
{
current[i][j] ? cout << " 0" : cout << " ";
neighbors = 0;
for (int deltay = 1; deltay < 2; deltay++)
for (int deltax = 1; deltax < 2; deltax++)
if (deltaxdeltay)
neighbors+=current[(i+deltax+x)%x][(j+deltay+y)%y];
if (current[i][j])
(neighbors == 2  neighbors == 3) ? next[i][j] = 1 : next[i][j] = 0;
else
neighbors == 3 ? next[i][j] = 1 : next[i][j] = 0;
}
cout << " XX";
cout << endl;
}
for (int a = 0; a < 2*x + 5; a++)
cout << "X";
for (int i = 0; i < y; i++)
for (int j = 0; j < x; j++)
current[i][j] = next[i][j];
system("cls");
}
}
Ok I've changed all the loop conditions and it seems to work now.
But there still is a problem when inputting grid sizes with a height larger than the width. Sometimes it makes super tiny grids, sometimes it works normal, and sometimes it crashes. Why?
I was so socially awkward in the past and it will haunt me for my entire life.

chris_c
 Posts: 963
 Joined: June 28th, 2014, 7:15 am
Post
by chris_c » July 3rd, 2020, 4:57 pm
gameoflifemaniac wrote: ↑July 3rd, 2020, 4:20 pm
Ok I've changed all the loop conditions and it seems to work now.
But there still is a problem when inputting grid sizes with a height larger than the width. Sometimes it makes super tiny grids, sometimes it works normal, and sometimes it crashes. Why?
I think I see the reason. You define your arrays like:
And access them like:
Therefore you need to make sure that i runs between 0 and x1, and that j runs between 0 and y1. Looks like you have this the wrong way round so will only work currently if x and y happen to be the same.

gameoflifemaniac
 Posts: 1096
 Joined: January 22nd, 2017, 11:17 am
 Location: There too
Post
by gameoflifemaniac » July 3rd, 2020, 5:14 pm
chris_c wrote: ↑July 3rd, 2020, 4:57 pm
gameoflifemaniac wrote: ↑July 3rd, 2020, 4:20 pm
Ok I've changed all the loop conditions and it seems to work now.
But there still is a problem when inputting grid sizes with a height larger than the width. Sometimes it makes super tiny grids, sometimes it works normal, and sometimes it crashes. Why?
I think I see the reason. You define your arrays like:
And access them like:
Therefore you need to make sure that i runs between 0 and x1, and that j runs between 0 and y1. Looks like you have this the wrong way round so will only work currently if x and y happen to be the same.
Code: Select all
#include <iostream>
#include <ctime>
#include <unistd.h>
#include <cstdlib>
using namespace std;
main()
{
int x,y;
cout << "Choose grid dimensions (x,y):";
cin >> x >> y;
int current[x][y];
int next[x][y];
int neighbors;
srand((int)time(0));
for (int i = 0; i < x; i++)
for (int j = 0; j < y; j++)
current[i][j]=(rand()%2);
while (true)
{
for (int a = 0; a < 2*y + 5; a++)
cout << "X";
cout << endl;
for (int i = 0; i < x; i++)
{
cout << "XX";
for (int j = 0; j < y; j++)
{
current[i][j] ? cout << " 0" : cout << " ";
neighbors = 0;
for (int deltay = 1; deltay < 2; deltay++)
for (int deltax = 1; deltax < 2; deltax++)
if (deltaxdeltay)
neighbors+=current[(i+deltax+x)%x][(j+deltay+y)%y];
if (current[i][j])
(neighbors == 2  neighbors == 3) ? next[i][j] = 1 : next[i][j] = 0;
else
neighbors == 3 ? next[i][j] = 1 : next[i][j] = 0;
}
cout << " XX";
cout << endl;
}
for (int a = 0; a < 2*y + 5; a++)
cout << "X";
for (int i = 0; i < x; i++)
for (int j = 0; j < y; j++)
current[i][j] = next[i][j];
system("cls");
}
}
I've switched x and y in the right places and it works perfectly. Thank you, bubblegum and rowett for your help!
I wanted to make this program to introduce myself into the programming language (it's only displayed in the console after all!). You taught me stuff I didn't learn from my online course, too.
I was so socially awkward in the past and it will haunt me for my entire life.