Cellular automaton doesn't make new cells - c++

I'm trying to make a program that is able to create every kind of cellular automatons, such as Conway's game of life and everything else too.
The graphic implementation works perfectly already, so I wouldn't waste your time with that (especially that it uses Allegro libraries), but the functions that counts the cells, doesn't work properly.
That's what I have at the moment. (the code is in order, I just break it with commentary to make everything clear for you)
Pre-definitions:
#define fldwidth 110
#define fldheight 140
A structure for graphics:
typedef struct tiles
{
unsigned char red, green, blue;
}tiles;
Two predefined structures: the RGB code of an alive and a dead test cell.
const tiles TEST_ALIVE = {200,0,0};
const tiles TEST_DEAD = {100,0,0};
A function that checks the color equality of a structure variable and a constant structure.
bool equality(tiles& a, const tiles& b)
{
if (a.red == b.red && a.green == b.green && a.blue == b.blue)
{
return true;
} else {
return false;
}
}
The main function. It gets two arrays of structures (first one is the current round, second one is where counting happens; in round loop, after the counting, b array will be copied into a array); when started, it does the following steps for every structures: counts, how many living cells it has in its neighborhood (if its a living cell, it starts from -1 to avoid counting itself as neighbours, otherwise it start from 0 regularly), then if itself is NOT a living test cell (but anything else) and has 5 neighbours, it becomes a living test cell; if itself is a living test cell and has 2 neighbours, it becomes a dead cell.
void Test(tiles arra[fldwidth][fldheight], tiles arrb[fldwidth][fldheight])
{
int a,b,i,j,counter;
for (j=1;j<fldheight-1;j++)
{
for (i=1;i<fldwidth-1;i++)
{
if (equality(arra[i][j], TEST_ALIVE) == true)
{
counter = -1;
} else {
counter = 0;
}
for (b=j-1;b<j+1;b++)
{
for (a=i-1;a<i+1;a++)
{
if (equality(arra[a][b], TEST_ALIVE) == true)
{
counter+=1;
}
}
}
arrb[i][j] = arra[i][j];
if (equality(arra[i][j], TEST_ALIVE) == false && counter == 5)
{
arrb[i][j] = TEST_ALIVE;
}
if (equality(arra[i][j], TEST_ALIVE) == true && counter == 2)
{
arrb[i][j] = TEST_DEAD;
}
}
}
}
The problem is that when the counting begins, every living cell becomes dead immediately in the first round and sometimes they just disappear, even without becoming dead cell (which is a darker red colour obviously), and it happens for almost every "counter == XY" check.
I've already got some tips, but I have no idea, why it doesn't work. Does it have logic failure? Because I can't see the mistake, even though it is there.
EDIT:
arra[fldwidth][fldheight]
is replaced by
arra[i][j]
and
arrb[i][j] = arra[i][j];
is added. Now everything stays as they were put.

Why do you access arra[fldwidth][fldheight] for the equality checks? This is outside of the array, one element behind the last element in the array! What you want to access is arra[i][j].
And unless arrb starts as a copy of arra, you probably want to add arrb[i][j] = arra[i][j]; in front of the two equality checks. That way if a cell doesn't meet any of the two state change rules, it will keep its current state.
Edit:
You also need to let the loop run between i-1 and i+1, so it should be: for (a = i-1; a <= i+1; a++), same for b!

I think your bug is in the line:
if (equality(arra[fldwidth][fldheight], TEST_ALIVE) == false && counter == 5)
This should be:
if (equality(arra[i][j], TEST_ALIVE) == false && counter == 5)
and similarly for the line:
if (equality(arra[fldwidth][fldheight], TEST_ALIVE) == true && counter == 2)

Related

Calling functions randomly using a vector

#assume everything needed is included
void Robot::moveRobot()
{
//calls a random directon for robot to move in
//if direction returns false (not able to move in that direction),
//call another random direction up to 4 times, excluding the one(s)
//already called. If they all return false, do not move the robot.
//vecDir = {moveForward(), moveBackward(), moveRight(), moveLeft()}
// = {0,1,2,3} initially
vector<int> vecDir{0,1,2,3}; //vetor indicating direction to move
int num = rand() % vecDir.size();
if(num == vecDir[0])
{
//if not able to move forward, try a different random direction
if(Robot::moveForward() == false)
{
vecDir.erase(num);
//here, vector will be vecDir={1,2,3}
}
}
else if(num == vecDir[1])
{
Robot::moveBackward();
}
else if(num == vecDir[2])
{
Robot::moveRight();
}
else //num == vecDir[3]
{
Robot::moveLeft();
}
}
Hi! I'm trying to randomly call these four functions within the moveRobot() function using a vector whose size is changed depending on if a direction cannot be called. I set moveForward() to the first element, moveBackward() to the second element, etc. If any of the moveXXXX() functions are false, I want to delete that element of the array. Example code shown
Example output:
//before doing anything, vecDir = {0,1,2,3}
int num = rand() % vecDir.size(); //assume num = 1, so it calls moveBackward()
//assume moveBackward() is false, so gets rid of that element
vecDir.erase(num); //new vecDir = {0,2,3};
// vecDir(0) would be moveForward(), vecDir(1) is now moveRight(), vecDir(1) is now moveLeft()
How would I continue this process to exhaust all elements and not move a robot? I know a for loop would be involved, but I cannot think of where to use it. I am also not sure if my thinking is correct by using if else for each element. Any help is appreciated, and I apologize if the question is confusing. I can clear it up if there are any misunderstandings.
Just have a vector of function pointers, rather then numbers.
void Robot::moveRobot() {
// vector of pointers to functions to move
std::vector<bool()> moves{
moveForward(), moveBackward(), moveRight(), moveLeft()
};
// we repeat the process until any moves are available.
while (moves.size() > 0) {
// pick a random move
const int num = rand() % moves.size();
// try to move
if (moves[num]() == true) {
// yay, we moved!
break;
}
// we did not move - remove current option and repeat
moves.erase(moves.begin() + num);
}
}

how accurate is find() and distance()

I think I read somewhere that distance() when returning the iterator position can be finicky. And sometimes it doesn't return the right position. I want to know if this is true or if I'm not using it right.
I'm trying to find when a particle in a vector of 21 is hovered. The idea is to switch the state of the others once one gets hovered.
I'm using find() to know when the particle is hovered, hence true.
vector<bool>::iterator it;
it = find(_tmp->isParticleHovered.begin(), _tmp->isParticleHovered.end(), true);
if (it != _tmp->isParticleHovered.end()){// we look if a particle is being hovered.
isHovered = true;// we use this to check internally the first boid
}else{
isHovered = false;
}
Now I also wanted to know not only when it was hovered but which one was hovered so I added this:
vector<bool>::iterator it;
it = find(_tmp->isParticleHovered.begin(), _tmp->isParticleHovered.end(), true);
if (it != _tmp->isParticleHovered.end()){// we look if a particle is being hovered.
l = distance(_tmp->isParticleHovered.begin(), it);
isHovered = true;// we use this to check internally the first boid
}else{
isHovered = false;
l = -1;
}
So knowing the index, I wanted to switch the states of the others so I came up with the following:
if ( l == -1){
if ( boidState5){
resetFamilyBoidState(_tmp);// makes all the particles go back to the same state
boidState2 = true;
boidState5 = false;
}
}else if ( l != -1){
if ( boidState2 ){
makeBoidStateless(_tmp, l);// I pass L, to this function, tell the function to switch all the particles to a different state except the one that is being hovered.
boidState5 = true;
boidState2 = false;
}
}
It will work for a couple of times but when I will hover from particle to particle rapidly it will get confused, and sometimes l will return 21 which will make it crash since the particle vector size is 21 - being 20 the latest container.
I came up with a solution without using neither find() nor distance():
int FamiliesController::returnInfoBoxState(){
for ( int i = 0; i < boidList.size(); i++){
if ( boidList[i]->boidState == 2){
return i;
}
}
return -1;
}
In the controller class I created a function that would return me the index number when that specific state was called, otherwise it would return -1. Using the same if statement it worked fine.
I'm curious to find about find() and distance(). Any clarification is much appreciated.
std::distance is exact. There is no room for doubt.
You are most likely misunderstanding its function, though. You said that it may return the "wrong position". It never returns positions anyway. An iterator is a position.
Also, you may want to check std::bitset<21>. It's more appropriate when the number of bits is fixed, and it has extra helper functions such as .reset()

Check if entire vector is zero

How could I check if every single element in a vector is zero without looping through them?
Current I have (In semi-MEW form):
What this attempts to do is check if all three values of the final vector (its three dimensional... year.) is all zeros, (At the origin), or if it equals any previous vector on all three values.
siteVisited = false; counter = 0;
while (counter < (walkHist.back().size()-1))
{
tdof = 1;
while (tdof <= dimensions)
{
if (walkHist.back().back().at(tdof-1) == 0)
{
siteVisited = true;
}
else
{
siteVisited = false;
break;
}
tdof++;
}
if (siteVisited)
{
goto visited;
}
tdof = 1;
while (tdof <= dimensions)
{
if (walkHist.back().back().at(tdof-1) == walkHist.back().at(counter).at(tdof-1))
{
siteVisited = true;
}
else
{
siteVisited = false;
break;
}
tdof++;
}
if (siteVisited)
{
visited:
...
}
counter++;
}
It depends on what you mean by looping, but this would work:
bool zeros = std::all_of(v.begin(), v.end(), [](int i) { return i==0; });
The reason for the check is important to know. If a zeroed array is important, and is checked regularly, it would be worth sub-classing vector to set a flag whenever a value is added or changed. This would add overhead to all adds, removes and modified, but would make the "is everything zero" test quick.
If your arrays are very often zeroed, it might then be worth writing your own sparse array class (probably based on map). When a non-zero item is added, or an element is changed to non-zero it is entered into the map. When changed to 0 it is removed. Now you know if all the elements are zero because the map will be empty. This will also have the benefit of using much less memory.
However, if the check for a zeroed array is comparatively rare, then any loop which breaks on non-zero will work well. It does, however, mean that the slowest check will be on all zero, which is worth keeping in mind.
You can also check if it equals a zero vector:
if(myVector == copyVector(myVector.size(), 0)){//this is a zero vector, do stuff}

possible misunderstanding of map iterators with for loops

very specific question I'm afraid (and I'm rather a novice, so apologies in advance):
I'm currently trying to finish my final project for a University object-oriented C++ course. I'm creating a student database to store exam results for students. My setup has loads of custom classes but all work perfectly (or at least do what I want them to do).
The project is set up as follows:
I have a "master" map of all "course"s, to which everything points to (so a course isn't duplicated if more than one student is taking it).
A "student" is a vector of pointers to "course"s and a corresponding double "result", and I have a master map of all students in the system.
a "degree" is a class of two vectors of pointers, one to courses offered by that degree, and one to students taking that degree. When a degree is created, it searches both master maps. If the first x letters in a course id matches the degree prefix, the course is added. If a student's subject matches the course name, the student is added.
My problem is this:
As I have some options to manually input courses and students after the initial setup from CSV files, I have writen a function to update my degrees if a course/result is added which should be included in a degree (see below). However, this code inevitably results in the first course and student being re-added (i.e. repeated) to the first degree the first time this function is called. this problem is not repeated if the function is called again. I have absolutely no idea why. A huge amount of time and cout statements later and I'm no closer to solving this. Am I missing something obvious about the first run? I may have set the loops up wrong (I'm not very familiar with maps). Don't hesitate to call me an idiot!
As I have said above, all the rest of the program is gravy, without this odd issue the program is fine. The problem does not appear to come from my print functions either.
Thank you in advance for your time.
//upgrade degrees function: used whenever new courses or students could be created by the user. It ticks through all stored degrees and scans cd and sd. If it finds an unstored course or student that should be stored, they are added.
void degree_database::update_degrees(course_database &cd, student_database &sd) {
cout << "updating degrees..." << endl;
bool found = false;
vector<degree>::iterator current;
for (current = start; current < end; ++current) {
//scan course list
map<string, course>::iterator x;
for (x = cd.get_start(); x != cd.get_end(); ++x) {
if (x->first.substr(0,3) == current->get_prefix().substr(0,3) || current->get_prefix() == "ALL") {
//check to see if course is already stored
vector<course*>::iterator a;
for (a = current->get_c_start(); a < current->get_c_end(); ++a) {
if (*a == &(x->second)) {
found = true;
break;
}
}
//if found == true, then while loop broke early (i.e. the course was already stored).
if (found == false) current->add_course(x->second);
found = false;
}
}
//scan student list
found = false;
map<string, student>::iterator y;
for (y = sd.get_start(); y != sd.get_end(); ++y) {
if (y->second.get_subject() == current->get_name() || current->get_name() == "All") {
//check to see if course is already stored
vector<student*>::iterator b;
for (b = current->get_s_start(); b < current->get_s_end(); ++b) {
if (*b == &(y->second)) {
found = true;
break;
}
}
//if found == true, then while loop broke early (i.e. the student was already stored).
if (found == false) current->add_student(y->second);
found = false;
}
}
}
cout << "done." << endl;
}
You store course by value in the course list and then you use pointer to this object in comparison. Apparently, you shoud store pointers in the map. I think (*a == &(x->second)) fails on the first run and pointer to the object from the course map is added to a degree object. On the second run, (*a == &(x->second)) succeeds and all looks ok. The same for student map.

I want to increment a counter by one in a while loop c++

I am trying to increment a lap counter in my game by one but because I have to put this code in the game loop my counter goes over every time by about 500 instead or moving up one. Here is my code. The checkpointPassed variable is only true when a checkpoint is passed through. I know this works and the checkpoint number is the current checkpoint and they start at 0.
if(checkpointNumber == 0 && checkpointPassed == true)
{
lapNumber += 1;
}
I can't post the game loop because it is quite large.
Any Help is appreciated.
EDIT
Here is some more of the code so you can see what I am trying to do.
if(distance > carRadius && markerCounter < 5000)
{
if(checkpointPassed == true)
{
markerCounter++;
}
}
if(checkpointNumber == 0 && checkpointPassed == true)
{
lapNumber += 1;
}
if(distance < carRadius)
{
markerCounter++;
cross->SetX(checkpointX);
cross->SetY(checkpointY);
cross->SetZ(checkpointZ);
checkpointNumber += 1;
checkpointPassed = true;
}
if(markerCounter > 4999)
{
checkpointPassed = false;
cross->SetPosition(0,-50,0);
markerCounter = 0;
}
Add another two variable called inCheckpoint, which stores whether the user is currently "inside" the checkpoint or not. This allows you to detect when the user enters a checkpoint and only increment the lapNumber then. The code would look as follows:
if(checkpointNumber == 0 && checkpointPassed == true)
{
if (inCheckpoint == false) /* previously not inside a checkpoint */
lapNumber += 1;
inCheckpoint = true;
}
else
{
inCheckpoint = false;
}
UPDATE: Don't rely on checkpointPassed:
if(distance < carRadius)
{
if (inCheckpoint == false) /* previously not inside a checkpoint */
lapNumber += 1;
inCheckpoint = true;
}
else
{
inCheckpoint = false;
}
You could set/pass a gueard value that indicates how many iterations in the game loop you are (or whether this is the first iteration). If it is the first iteration (within the current lap), increment the variable as you do now, otherwise don't
You will need to reset this guard value for each lap -- e.g. right after you increment lapNumber.
You might need to cancel the 'checkpointPassed` state.
if (checkpointNumber == 0 && checkpointPassed == true)
{
lapNumber += 1;
checkpointPassed = false;
}
This means that you won't be counting the lap again until the next time a checkpoint is passed, which is presumably when you need it counted.
However, if you need checkpointPassed true later in the loop, then you'll need to think whether you need yet another variable, such as lapCounted, which is set to false when checkpointPassed is set to true, and reset to true by the code above (instead of setting checkpointPassed, not as well as setting it).
If I understand correctly what you said, your 'if' statement is inside the main loop and when you pass a checkpoint, 'checkpointPassed' becomes true. For how long?
If it stays 'true' for a few iterations, then each time your game loop does an iteration,your lap counter is incremented. In this case, you should either set checkPointPassed to false at the end of the iteration, or use a different variable, that you set to true at the same time that checkPointPassed becomes true and false after incrementing.
If this does not answer your question, can you give a little more context as with only this part of the code, it is hard to figure out what you want to do.