Called function clears changes of previous one - c++

I'm working on a cellular automaton where changes happen in every rounds. Obviously, I made a loop for it - basically it works, fortunately, but if I want to add another type of cells to the map, the whole thing doesn't work! I mean, one type of cells works, but the other doesn't do anything: The game begins and e.g. in this example, the Conway-automaton starts growing, but the red test-cells are just staying without any changes.
These are the two functions (with predefined things):
#define fldwidth 110
#define fldheight 140
//struktúra, aztán a sejtek definíciója
typedef struct tiles
{
unsigned char red, green, blue;
}tiles;
const tiles TEST_ALIVE = {255,0,0};
const tiles TEST_DEAD = {50,0,0};
const tiles CONWAY_ALIVE = {0,255,0};
const tiles CONWAY_DEAD = {0,50,0};
//Maes módszere a struktúrák egyenlőségének vizsgálatára
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;
}
}
//sejttípus 1.: tesztsejt: minden magányos vagy túlbuzgó sejt meghal
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];
//itt a sejtek szabályai jönnek; mindig a születést tesszük előre, utána a halált!
if (equality(&arra[i][j], &TEST_ALIVE) == false && counter >= 2)
{
arrb[i][j] = TEST_ALIVE;
}
if (equality(&arra[i][j], &TEST_ALIVE) == true && (counter == 0 || counter > 6))
{
arrb[i][j] = TEST_DEAD;
}
}
}
}
//sejttípus 2.: Conway életjátéka
void Conway(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], &CONWAY_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], &CONWAY_ALIVE) == true)
{
counter+=1;
}
}
}
arrb[i][j] = arra[i][j];
//itt a sejtek szabályai jönnek; mindig a születést tesszük előre, utána a halált!
if (equality(&arra[i][j], &CONWAY_ALIVE) == false && counter == 3)
{
arrb[i][j] = CONWAY_ALIVE;
}
if (equality(&arra[i][j], &CONWAY_ALIVE) == true && (counter != 2 && counter != 3))
{
arrb[i][j] = CONWAY_DEAD;
}
}
}
}
and this is the loop itself:
while(!end)
{
al_wait_for_event_timed(event_queue,&asd,0.001); //várakozás
if(asd.type == ALLEGRO_EVENT_KEY_DOWN)
{
if(asd.keyboard.keycode == ALLEGRO_KEY_ENTER)
{
Test(fielda,fieldb);
Conway(fielda,fieldb);
end = false;
round++;
for (j = 0; j < fldheight; j++)
{
for (i = 0; i < fldwidth; i++)
{
fielda[i][j] = fieldb[i][j];
}
}
}
}
for (j = 0; j < fldheight; j++)
{
for (i = 0; i < fldwidth; i++)
{
al_draw_filled_rectangle(20 + (4*i), 20 + (4*j), 24 + (4*i), 24 + (4*j), al_map_rgb(fielda[i][j].red, fielda[i][j].green, fielda[i][j].blue));
}
}
}
Can you tell me what is wrong with it? Or maybe the problem is not in the loop?

Your problem is that the second function you call reverses all the changes made by the first function. That is why you see only one working.
The best way to get both working it to let each function operate only on one colour channel. Test uses only the red colour channel (both for reading and changing), while Conway uses only the green colour channel. Be prepared to see cells with different colours: these were affected by both functions.

Related

While Overloading The << Operator Was It Correctly Formatted?

I have been getting outputs and sometimes even getting the complete output, however I don't quite understand why I'd be getting said outputs. I want to believe it has something to do with my overloading of said operator "<<" when I perform the operation of outputting the information in the "OpenSea" object. Any leads would be tremendously helpful and thank you for your time!
Note: I included only the necessary files but will update if you think you need more to understand the full scope of my situation. Also there is no need to give me tips on how to format my code as I know a lot of it can be reworked for optimization.
main.cpp
#include "aquaClasses.h"
#include "aquaFish.h"
#include "aquaKillerWhale.h"
#include "aquaPenguin.h"
#include "aquaSea.h"
using namespace std;
int main ()
{
srand (time (NULL));
// Simulation
Sea OpenSea (17, 17);
cout << OpenSea;
}
aquaClasses.h <-- "main" header file
#ifndef AQUACLASSES_H
#define AQUACLASSES_H
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <iomanip>
// Constants
const short int AMT_FISH = 200;
const short int AMT_KWHALES = 2;
const short int AMT_PENGS = 50;
const short int MAX_SIM_INTERATIONS = 10000;
const short int MAX_SEA_GRID = 25;
const short int MAX_SEA_SIZE = 625;
// Functions
template <typename TYPE> int calculate_distance (int obj1_x, int obj1_y,
TYPE obj2);
template <typename TYPE> int calculate_direction (int obj1_x, int obj1_y,
TYPE obj2);
#endif
aquaSea.h
#ifndef AQUASEA_H
#define AQUASEA_H
// Forward Declarations to circumvent circular dependency
class Fish;
class Penguin;
class Killer_Whale;
class Sea
{
private:
char m_grid [MAX_SEA_GRID][MAX_SEA_GRID];
int m_fish;
int m_kwhales;
int m_pengs;
int m_size;
int m_height;
int m_width;
void clear ();
void populate ();
public:
Sea (const int grid_size_height, const int grid_size_width);
friend std::ostream &operator<<(std::ostream &os, Sea obj);
int getHeight () const {return m_height;};
int getWidth () const {return m_width;};
void setCell (int obj_x, int obj_y, char cell_symbol);
// Appropriate accessor/mutator functions
};
#endif
aquaSea.cpp
#include "aquaClasses.h"
#include "aquaFish.h"
#include "aquaPenguin.h"
#include "aquaKillerWhale.h"
#include "aquaSea.h"
using namespace std;
// - [row][column]
Sea::Sea (const int grid_size_height, const int grid_size_width)
{
m_fish = 200;
m_kwhales = 2;
m_pengs = 50;
if ((grid_size_height || grid_size_width) <= 0)
{
if (grid_size_height <= 0 && grid_size_width > 0)
{
m_size = MAX_SEA_GRID * grid_size_width;
m_width = grid_size_width;
m_height = MAX_SEA_GRID;
}
else if (grid_size_width <= 0 && grid_size_height > 0)
{
m_size = MAX_SEA_GRID * grid_size_height;
m_width = MAX_SEA_GRID;
m_height = grid_size_height;
}
else if (grid_size_height <= 0 && grid_size_width <= 0)
{
m_size = MAX_SEA_GRID * MAX_SEA_GRID;
m_height = MAX_SEA_GRID;
m_width = MAX_SEA_GRID;
}
}
else
{
m_size = grid_size_height * grid_size_width;
m_height = grid_size_height;
m_width = grid_size_width;
}
clear ();
populate ();
}
ostream &operator<<(ostream &os, Sea obj)
{
os << "Sea Height: " << obj.m_width << endl << "Sea Wdith: "
<< obj.m_width << endl << "Sea Size: " << obj.m_size
<< endl;
os << "Grid View: " << endl;
for (int i = 0; i < obj.m_height; i++)
{
for (int j = 0; j < obj.m_width; j++)
{
os << obj.m_grid [i][j];
}
os << endl;
}
return os;
}
void Sea::clear ()
{
for (int i = 0; i < m_height; i++)
{
for (int j = 0; j < m_width; j++)
{
m_grid[i][j] = 'O';
}
}
return;
}
void Sea::populate ()
{
// Special simluation variables
bool applyFish = true;
bool applyKWhales = false;
bool applyPengs = false;
int amtFishPop = 35;
int amtKWhalesPop = 2;
int amtPengPop = 20;
int index = 0;
int randGridRow = 0;
int randGridCol = 0;
int totalPop = amtFishPop + amtKWhalesPop + amtPengPop;
Fish arr_fish [AMT_FISH];
Killer_Whale arr_kwhales [AMT_KWHALES];
Penguin arr_pengs [AMT_PENGS];
for (int i = 0; i < totalPop; i++)
{
// Grab random place on grid to apply and check if grid plot is open
randGridRow = rand () % 16;
randGridCol = rand () % 16;
while (m_grid [randGridRow][randGridCol] != 'O')
{
randGridRow = rand () % 16;
randGridCol = rand () % 16;
}
// Populate and Update Fish
if (amtFishPop > 0 && applyFish == true)
{
arr_fish[index].setX (randGridCol);
arr_fish[index].setY (randGridRow);
setCell (arr_fish[index].getX (), arr_fish[index].getY (), 'F');
amtFishPop--;
index++;
}
else if (amtFishPop == 0)
{
applyFish = false;
applyKWhales = true;
index = 0;
}
// Populate and Update Killer Whales
if (amtKWhalesPop > 0 && applyKWhales == true)
{
arr_kwhales[index].setX (randGridCol);
arr_kwhales[index].setY (randGridRow);
setCell (arr_kwhales[index].getX (), arr_kwhales[index].getY (), 'K');
amtKWhalesPop--;
index++;
}
else if (amtKWhalesPop == 0)
{
applyKWhales = false;
applyPengs = true;
index = 0;
}
// Populate and Update Penguins
if (amtPengPop > 0 && applyPengs == true)
{
arr_pengs[index].setX (randGridCol);
arr_pengs[index].setY (randGridRow);
setCell (arr_pengs[index].getX (), arr_pengs[index].getY (), 'P');
amtPengPop--;
index++;
}
else if (amtPengPop == 0)
{
applyPengs = false;
index = 0;
}
}
return;
}
void Sea::setCell (int obj_x, int obj_y, char cell_symbol)
{
m_grid [obj_x][obj_y] = cell_symbol;
return;
}
Types of Output
Wanted:
- Image
Unwanted:
- Image
STOP! AFTER THIS POINT IS OPTIONAL CODE TO FURTHER UNDERSTAND THE SITUATION
Other Code Of Reference If You Want But I Don't Think It's Needed
aquaFish.h
#ifndef AQUAFISH_H
#define AQUAFISH_H
class Fish
{
private:
int m_fish_amt_food;
int m_fish_x;
int m_fish_y;
bool m_fish_alive;
public:
Fish ();
int getX () const {return m_fish_x;};
int getY () const {return m_fish_y;};
void setX (int new_x) {m_fish_x = new_x;};
void setY (int new_y) {m_fish_y = new_y;};
int getFishAmtFood () const {return m_fish_amt_food;};
void move ();
};
#endif
aquaFish.cpp
#include "aquaClasses.h"
#include "aquaFish.h"
using namespace std;
Fish::Fish ()
{
int randNum = rand () % 10 + 1;
m_fish_amt_food = randNum;
m_fish_x = -1;
m_fish_y = -1;
}
void Fish::move ()
{
int randDir = rand () % 8 + 1;
if (randDir == 1)
{
m_fish_y++;
}
else if (randDir == 2)
{
m_fish_x++;
m_fish_y++;
}
else if (randDir == 3)
{
m_fish_x++;
}
else if (randDir == 4)
{
m_fish_x++;
m_fish_y--;
}
else if (randDir == 5)
{
m_fish_y--;
}
else if (randDir == 6)
{
m_fish_x--;
m_fish_y--;
}
else if (randDir == 7)
{
m_fish_x--;
}
else if (randDir == 8)
{
m_fish_x--;
m_fish_y++;
}
return;
}
aquaPenguin.h
#ifndef AQUAPENGUIN_H
#define AQUAPENGUIN_H
// Forward Declarations to circumvent circular dependancy
class Sea;
class Fish;
class Killer_Whale;
class Penguin
{
private:
int m_peng_health; // 0-100
int m_peng_x;
int m_peng_y;
bool m_peng_alive;
public:
Penguin ();
int getX () const {return m_peng_x;};
int getY () const {return m_peng_y;};
void setX (int new_x) {m_peng_x = new_x;};
void setY (int new_y) {m_peng_y = new_y;};
void move (Sea obj_sea, Fish arr_fish [], int arr_fish_size,
Killer_Whale arr_kwhale [], int arr_kwhale_size);
};
#endif
aquaPenguin.cpp
#include "aquaClasses.h"
#include "aquaFish.h"
#include "aquaKillerWhale.h"
#include "aquaPenguin.h"
#include "aquaSea.h"
#include "aquaFunctions.cpp"
using namespace std;
Penguin::Penguin ()
{
m_peng_health = rand () % (81 - 60) + 60;
m_peng_x = -1;
m_peng_y = -1;
m_peng_alive = false;
}
void Penguin::move (Sea obj_sea, Fish arr_fish [], int arr_fish_size,
Killer_Whale arr_kwhale [], int arr_kwhale_size)
{
int actuDistToFish = 8;
int currDistToFish = 0;
int tempMoveX = 0;
int tempMoveY = 0;
int amtMove = 0;
int direction = 0;
int fishIndex = 0;
bool moveAwayKillerWhale = false;
bool fishInRange = false;
// Determine amount of cells to move in sea
if (m_peng_health >= 81 && m_peng_health <= 100)
{
amtMove = 5;
}
else if (m_peng_health >= 61 && m_peng_health <= 80)
{
amtMove = 4;
}
else if (m_peng_health >= 41 && m_peng_health <= 60)
{
amtMove = 3;
}
else if (m_peng_health >= 21 && m_peng_health <= 40)
{
amtMove = 2;
}
else if (m_peng_health >= 1 && m_peng_health <= 20)
{
amtMove = 1;
}
else
{
cout << "Chicken of the sea at: " << m_peng_x << " " << m_peng_y
<< endl;
return;
}
// ADD: Find if any killer whales are near first and if so then penguin just moves away
// Find if any fish are near <-- THIS IS WRONG, YOU NEED TO FIND THE CLOSEST FISH
for (int i = 0; i < arr_fish_size; i++)
{
currDistToFish = calculate_distance (m_peng_x, m_peng_y,
arr_fish[i]);
if (currDistToFish <= 8)
{
if (currDistToFish < actuDistToFish)
{
actuDistToFish = currDistToFish;
fishIndex = i;
fishInRange = true;
}
}
}
// ADD: If fish and whale are found do something, we decide. Otherwise move randomly Peng See Dist 8.0
// ADD Move 1 tick then gauge situation again
for (int k = 0; k < amtMove; k++)
{
if (fishInRange == true && moveAwayKillerWhale == false)
{
tempMoveX = m_peng_x; // temp used for storing before changing
tempMoveY = m_peng_y; // temp used for storing before changing
direction = calculate_direction (m_peng_x, m_peng_y,
arr_fish[fishIndex]);
cout << "Penguin pos before moving: " << m_peng_x << ","
<< m_peng_y << endl;
cout << "Closest Fish pos: " << arr_fish[fishIndex].getX () << ","
<< arr_fish[fishIndex].getY () << endl;
if (m_peng_health == 0)
{
cout << "Chicken of the sea at: " << m_peng_x << " " << m_peng_y
<< endl;
return;
}
if (direction == 1)
{
actuDistToFish--;
m_peng_health--;
tempMoveY++;
}
else if (direction == 2)
{
actuDistToFish--;
m_peng_health--;
tempMoveX++;
tempMoveY++;
}
else if (direction == 3)
{
actuDistToFish--;
m_peng_health--;
tempMoveX++;
}
else if (direction == 4)
{
actuDistToFish--;
m_peng_health--;
tempMoveX++;
tempMoveY--;
}
else if (direction == 5)
{
actuDistToFish--;
m_peng_health--;
tempMoveY--;
}
else if (direction == 6)
{
actuDistToFish--;
m_peng_health--;
tempMoveX--;
tempMoveY--;
}
else if (direction == 7)
{
actuDistToFish--;
m_peng_health--;
tempMoveX--;
}
else if (direction == 8)
{
actuDistToFish--;
m_peng_health--;
tempMoveX--;
tempMoveY++;
}
else
{
cout << "[ERROR]: Penguin direction messed up." << endl;
}
// MODIFY: Lastly check if out of bounds and then move peng
if (tempMoveX > obj_sea.getWidth ()
|| tempMoveX < -(obj_sea.getWidth ()))
{
m_peng_x = m_peng_x; // AKA dont move
m_peng_y = m_peng_y;
}
else if (tempMoveY > obj_sea.getHeight ()
|| tempMoveY < -(obj_sea.getHeight ()))
{
m_peng_x = m_peng_x; // AKA dont move
m_peng_y = m_peng_y;
}
else
{
obj_sea.setCell (m_peng_x, m_peng_y, 'O'); // Delete old cell
m_peng_x = tempMoveX;
m_peng_y = tempMoveY;
obj_sea.setCell (m_peng_x, m_peng_y, 'P'); // Set new cell
}
// Check if peng eats after moving
if (actuDistToFish == 0)
{
// Stop moving
amtMove = 0;
// Eat fish
m_peng_health += arr_fish[fishIndex].getFishAmtFood ();
// ADD: Remove fish from grid
}
cout << "Penguin pos after moving: " << m_peng_x << ","
<< m_peng_y << endl;
}
else if (fishInRange == false && moveAwayKillerWhale == true)
{
}
else if (fishInRange == false && moveAwayKillerWhale == false)
{
// If no fish, movement is random, else it's towards fish how ever many
// step the penguin can go
direction = rand () % 8 + 1;
if (direction == 1)
{
m_peng_y++;
}
else if (direction == 2)
{
m_peng_x++;
m_peng_y++;
}
else if (direction == 3)
{
m_peng_x++;
}
else if (direction == 4)
{
m_peng_x++;
m_peng_y--;
}
else if (direction == 5)
{
m_peng_y--;
}
else if (direction == 6)
{
m_peng_x--;
m_peng_y--;
}
else if (direction == 7)
{
m_peng_x--;
}
else if (direction == 8)
{
m_peng_x--;
m_peng_y++;
}
else
{
cout << "[ERROR]: Penguin random direction messed up." << endl;
}
}
}
return;
}
aquaKillerWhale.h
#ifndef AQUAKILLERWHALE_H
#define AQUAKILLERWHALE_H
class Penguin;
class Killer_Whale
{
private:
int m_kwhale_amt_pengs;
int m_kwhale_x;
int m_kwhale_y;
public:
Killer_Whale ();
int getX () const {return m_kwhale_x;};
int getY () const {return m_kwhale_y;};
void setX (int new_x) {m_kwhale_x = new_x;};
void setY (int new_y) {m_kwhale_y = new_y;};
void move (Penguin arr_peng []);
};
#endif
aquaKillerWhale.cpp
#include "aquaClasses.h"
#include "aquaKillerWhale.h"
#include "aquaPenguin.h"
using namespace std;
Killer_Whale::Killer_Whale ()
{
m_kwhale_x = -1;
m_kwhale_y = -1;
}
void Killer_Whale::move (Penguin arr_peng [])
{
return;
}
aquaFunctions.cpp
#include "aquaClasses.h"
using namespace std;
// Functions
template <typename TYPE>
int calculate_direction (int obj1_x, int obj1_y, TYPE obj2)
{
int calculatedX = obj2.getX () - obj1_x;
int calculatedY = obj2.getY () - obj1_y;
int direction = 0;
if (calculatedX == 0 && calculatedY > 0)
{
direction = 1;
}
else if (calculatedX > 0 && calculatedY > 0)
{
direction = 2;
}
else if (calculatedX > 0 && calculatedY == 0)
{
direction = 3;
}
else if (calculatedX > 0 && calculatedY < 0)
{
direction = 4;
}
else if (calculatedX == 0 && calculatedY < 0)
{
direction = 5;
}
else if (calculatedX < 0 && calculatedY < 0)
{
direction = 6;
}
else if (calculatedX < 0 && calculatedY == 0)
{
direction = 7;
}
else if (calculatedX < 0 && calculatedY > 0)
{
direction = 8;
}
else
{
cout << "[ERROR]: Direction calculation failed." << endl;
}
return direction;
}
template <typename TYPE>
int calculate_distance (int obj1_x, int obj1_y, TYPE obj2)
{
int distance = sqrt ((obj1_x - obj2.getX ())
* (obj1_x - obj2.getX ())
+ (obj1_y - obj2.getY ())
* (obj1_y - obj2.getY ()));
return distance;
}

C++ adding borders on monsters (C++ text-based game)

void Map::Movement()
{
int ch;
switch (ch = _getch())
{
case KEY_W: //up
if (Player::posy != 1)
{
if (AboveM == false)
{
Player::posy--;
DisplayMap();
}
}
break;
case KEY_S: //down
if (Player::posy != 20)
{
if (BelowM == false)
{
Player::posy++;
DisplayMap();
}
}
break;
case KEY_A: //left
if (Player::posx != 1)
{
if (LeftM == false)
{
Player::posx--;
DisplayMap();
}
}
break;
case KEY_D: //right
if (Player::posx != 20)
{
if (RightM == false)
{
Player::posx++;
DisplayMap();
}
}
break;
I can't for the life of me figure out where to put this so that the borders for the mob will work correctly (first question I know it isn't asked well since I haven't added the rest of the code but it should be simple to figure out)I've been putting it every place I could think of the last week or so as well as trying out everything else I could that would run I either get weird random errors or it runs as if the monster as no borders at all.
if ((Player::posy = Enemy::enemyBuild::posy) && (Player::posx = Enemy::enemyBuild::posx +1))
{
bool RightM = true;
}
if ((Player::posy = Enemy::enemyBuild::posy) && (Player::posx = Enemy::enemyBuild::posx -1))
{
bool LeftM = true;
}
if ((Player::posx = Enemy::enemyBuild::posx) && (Player::posy = Enemy::enemyBuild::posy +1))
{
bool BelowM = true;
}
if ((Player::posx = Enemy::enemyBuild::posx) && (Player::posy = Enemy::enemyBuild::posy -1))
{
bool AboveM = true;
}

Combining for-loops in C++

I am making a GoBoard and want to check if the Black player has won the game. I made four for loops to check, whether there are 5 stones in a row horizontally, vertically or diagonally. I would like to combine them however, to save some lines of code. How to do it? Is it possible to simply check for the White player as well using the same for loops or should I make a new bool for the White player?
class goBoard {
private:
boardSquare* entrance; // A pointer containing the address of the boardSquare-object at the top left of the grid.
void zip (boardSquare*, boardSquare*);
boardSquare* makeRow (); //(int amount)?
int m, n;
public:
//goBoard ();
goBoard (int numberOfRows, int numberOfColumns);
~goBoard ();
void build ();
void computer (char colour);
bool squareEmpty (int x, int y);
void human (char colour);
void print ();
bool done ();
bool won ();
void makeMove (int x, int y, char colour);
};//class goBoardbool
goBoard::wonBlack () {
boardSquare* currentSquare = entrance; //assuming that the player starts at the entrance
bool nextSquare = true;
if ((*currentSquare).colour == 'B') {
for (int i = 0; i <= 4; i++) {
if (nextSquare == true) {
currentSquare = (*currentSquare).neighbours[2]; //.neighbours[2] is a pointer to the square to the right of the current square
if ((*currentSquare).colour != 'B')
nextSquare = false;
}
}
for (int i = 0; i <= 4; i++) {
if (nextSquare == true) {
currentSquare = (*currentSquare).neighbours[4];
if ((*currentSquare).colour != 'B')
nextSquare = false;
}
}
for (int i = 0; i <= 4; i++) {
if (nextSquare == true) {
currentSquare = (*(*currentSquare).neighbours[2]).neighbours[4];
if ((*currentSquare).colour != 'B')
nextSquare = false;
}
}
for (int i = 0; i <= 4; i++) {
if (nextSquare == true) {
currentSquare = (*(*currentSquare).neighbours[6]).neighbours[4];
if ((*currentSquare).colour != 'B')
nextSquare = false;
}
}
if (nextSquare == true)
return true;
}
return false;
}//goBoard::won
If you want to reduce the linecount, I would go for something on this line:
enum class Direction {vertical, horizontal, downRight, upRight};
enum class Sign {negative, zero, positive}
enum class Semen {white, black};
template <typename Elem>
unsigned int howManyInARow(Direction direction, Sign sign, Elem elem, Semen semen){
unsigned int ret = 0;
if(elem == semen){
ret = 1;
}
if(negative != sign)
ret += howManInARow(direction, positive, elem.getNeighbour(direction, positive), semen);
if(positive != sign)
ret += howManInARow(direction, negative, elem.getNeighbour(direction, negative), semen);
return ret;
}
Could'nt test it because I don't have the elements. Give it a try and I can elaborate on it if you like it

Called function clears changes of previous one

I'm working on a cellular automaton where changes happen in every rounds. Obviously, I made a loop for it - basically it works, fortunately, but if I want to add another type of cells to the map, one type of cells works, but the other doesn't do anything: the game begins and e.g. in this example, the Conway-automaton starts growing, but the red test-cells are just staying without any changes.
#define fldwidth 110
#define fldheight 140
typedef struct tiles
{
unsigned char red, green, blue;
}tiles;
const tiles TEST_ALIVE = {255,0,0};
const tiles TEST_DEAD = {50,0,0};
const tiles CONWAY_ALIVE = {0,255,0};
const tiles CONWAY_DEAD = {0,50,0};
//Maes módszere a struktúrák egyenlőségének vizsgálatára
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;
}
}
//sejttípus 1.: tesztsejt: minden magányos vagy túlbuzgó sejt meghal
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];
//itt a sejtek szabályai jönnek; mindig a születést tesszük előre, utána a halált!
if (equality(&arra[i][j], &TEST_ALIVE) == false && counter >= 2)
{
arrb[i][j] = TEST_ALIVE;
}
if (equality(&arra[i][j], &TEST_ALIVE) == true && (counter == 0 || counter > 6))
{
arrb[i][j] = TEST_DEAD;
}
}
}
}
//sejttípus 2.: Conway életjátéka
void Conway(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], &CONWAY_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], &CONWAY_ALIVE) == true)
{
counter+=1;
}
}
}
arrb[i][j] = arra[i][j];
//itt a sejtek szabályai jönnek; mindig a születést tesszük előre, utána a halált!
if (equality(&arra[i][j], &CONWAY_ALIVE) == false && counter == 3)
{
arrb[i][j] = CONWAY_ALIVE;
}
if (equality(&arra[i][j], &CONWAY_ALIVE) == true && (counter != 2 && counter != 3))
{
arrb[i][j] = CONWAY_DEAD;
}
}
}
}
This is content of the loop:
Test(fielda,fieldb);
Conway(fielda,fieldb);
end = false;
round++;
for (j = 0; j < fldheight; j++)
{
for (i = 0; i < fldwidth; i++)
{
fielda[i][j] = fieldb[i][j];
}
}
As I mentioned, in this example, Conway cells grow, but Test cells just stay. How to make them work simultaneously?
(I use Allegro libraries so if that has something for this problem, feel free to share with me!)
Test(fielda,fieldb); sets every cell of fieldb based on the current value of fielda. And then Conway(fielda,fieldb); sets every cell of fieldb based on the current value of fielda, overwriting fieldb so that everything Test did is gone. One way to fix this is to change your loop to:
Test(fielda,fieldb);
Conway(fieldb,fielda); //switched the parameters
end = false;
round++;
//there is no need to copy fieldb to fielda here because Conway already did
But this might not be the right fix depending on exactly how you want test and conway to interact with each other.

C++ Rectangle to rectangle Collision

I'm having a really bad time here looking for the error in my code.
My collision detection won't work here even the algorithm I searched in Google.
void PollEvents()
{
for (int i = 0;i < NUMBER_OF_BLOCKS; ++i)
{
Rectangle& a = blocks[i];
if (mouse.state == GLFW_PRESS)
{
//look for any block to grab
if (mouse.leftClick && !blocks[selectedBlock].Grab() &&
a.Hover(mouse.pos.x, mouse.pos.y))
{
//prevent grabbing another block
if (i != selectedBlock) {
selectedBlock = i;
}
a.Grab() = true;
if (a.IsTypeHorizontal()) {
diff = mouse.pos.x - a.Left();
} else {
diff = mouse.pos.y - a.Top();
}
}
if (a.Grab())
{
for (int j = 0;j < NUMBER_OF_BLOCKS; ++j)
{
//skip for any self-checking
if (i == j) continue;
Rectangle& b = blocks[j];
//check for rectangle collision
if (!a.Collide(b) || b.Collide(a)) {
//j++;
//how does this block will move.
if (a.IsTypeVertical()) {
a.SetY(mouse.pos.y - diff);
} else {
a.SetX(mouse.pos.x - diff);
}
} else {
switch (a.sideHit)
{
case UP:
//a.SetY(b.Bottom());
printf("UP\n");
break;
case DOWN:
//a.SetY(b.Top() + a.GetHeight());
printf("DOWN\n");
break;
case LEFT:
//a.SetX(b.Right());
printf("LEFT\n");
break;
case RIGHT:
//a.SetX(b.Left() - a.GetWidth());
printf("RIGHT\n");
break;
}
}
//check for bound collision
a.BoundCheck(1.f);
}
}
} else {
a.Grab() = false;
}
}
}
Collision detection:
bool Rectangle::Collide(const Rectangle& r) {
if (IsTypeHorizontal()) {
if (r.Hover(Left(), Top()) && r.Hover(Right(), Top())) {
sideHit = UP;
return true;
} else if (r.Hover(Right(), Bottom()) && r.Hover(Left(), Bottom())) {
sideHit = DOWN;
return true;
}
// } else if (r.Hover(Left(), Top())) {
// sideHit = UP;
// return true;
// } else if (r.Hover(Right(), Top())) {
// sideHit = UP;
// return true;
// } else if (r.Hover(Right(), Bottom())) {
// sideHit = DOWN;
// return true;
// } else if (r.Hover(Left(), Bottom())) {
// sideHit = DOWN;
// return true;
// }
} else {
if (r.Hover(Left(), Top()) && r.Hover(Left(), Bottom())) {
sideHit = LEFT;
return true;
} else if (r.Hover(Right(), Top()) && r.Hover(Right(), Bottom())) {
sideHit = RIGHT;
return true;
}
// } else if (r.Hover(Left(), Top())) {
// sideHit = LEFT;
// return true;
// } else if (r.Hover(Left(), Bottom())) {
// sideHit = LEFT;
// return true;
// } else if (r.Hover(Right(), Top())) {
// sideHit = RIGHT;
// return true;
// } else if (r.Hover(Right(), Bottom())) {
// sideHit = RIGHT;
// return true;
// }
}
return false;
}
Code for Hover:
inline float Hover(float X, float Y) const {
return X >= Left() &&
X <= Right() &&
Y >= Bottom() &&
Y <= Top();
}
I'm trying to make my own unblockme.
Please help me on my collision-detection. It's been 3 days now since I got stuck in this problem.
UPDATE
I have found out the problem why all rect-rect collision detection won't work in my program.
Bug:
if (!a.Collide(b)) {
//Move()
} else {
//Resolve collision
}
This one should be
if (!Rectangle::Collide(a, b)) {
//Move()
} else {
//Resolve collision
}
Making the Collide() a static member of Rectangle because, as you can see in my implementation of Collide(), it bases its decision on its own member so a.Hover(b.x, b.y) doesn't make any sense.
Hope this helps a little bit to all newbies like me.
To do rect/rect collision detection, if any of one (edges parallel to x and y axis) rect's four points is inside the other rect, we have a collision.
An easier way than to check each of the four points is to check if one X edge is between both the other rect's X edges, and if one Y edge is between both the other rect's Y edges - if both are true, we have a collision (because the two edges must meet at a point inside of the other rect). So we just check this in both directions:
bool isclamped(float mid, float A, float B)
{
if (A > B)
{
return mid >= B && mid <= A;
}
return mid >= A && mid <= B;
}
bool checkcollisiononeway(rect rectA, rect rectB)
{
if (isclamped(rectA.left, rectB.left, rectB.right)
|| isclamped(rectA.right, rectB.left, rectB.right))
&& (isclamped(rectA.bottom, rectB.bottom, rectB.top)
|| isclamped(rectA.top, rectB.bottom, rectB.top))
{
return true;
}
return false;
}
bool checkcollisionbothways(rect rectA, rect rectB)
{
return checkcollisiononeway(rectA, rectB) || checkcollisiononeway(rectB, rectA);
}
To determine the angle of collision after detecting a collision, find the angle between their two centers using atan2(rectA.y - rectB.y, rectA.x - rectB.x) (the angle is returned in radians, not in degrees)