This is my first question on this site. I learn programming for a year and I always found a answer for my problem in projects. I know that this is REALLY simple problem and here is a code:
#include "stdafx.h"
#include "Wave.h"
Wave::~Wave()
{
}
void Wave::setEnemyCount(int count) {
nemyCount = count;
}
bool Wave::createWave() {
for (int i = 0; i < enemyCount; i++) {
enemyArray.push_back(Enemy());
}
for (int i = 0; i < enemyArray.size(); i++) {
int randomPositionX = rand() % 150 + 10;
int randomPositionY = rand() % 50 + 10;
if (!enemyArray.at(i).init(randomPositionX, randomPositionY)) {
std::cout << "Create wave(init enemies) - failed\n";
return false;
}
}
return true;
}
void Wave::drawWave(Window* window) {
window->setCursor({ 0, 2 });
window->setColor(Window::Color::RED);
std::cout << "Enemies: " << enemyArray.size();
window->setColor(Window::Color::WHITE);
for (int i = 0; i < enemyArray.size(); i++) {
enemyArray.at(i).draw(window);
//std::cout << i;
}
}
void Wave::update(Bullet* bullet, Player* player) {
for (int i = 0; i < enemyArray.size(); i++) {
if (player->checkShoot()) {
if ((bullet->getPositionX() >= enemyArray.at(i).getPositionX() && bullet->getPositionX() <= enemyArray.at(i).getPositionX() + 5)) {
if ((bullet->getPositionY() >= enemyArray.at(i).getPositionY() && bullet->getPositionY() <= enemyArray.at(i).getPositionY() + 5)) {
player->addScore(10);
enemyArray.erase(enemyArray.begin() + i);
}
}
}
}
if (enemyArray.size() <= 0) {
std::cout << "WAVE COMPLETE";
Sleep(2000);
enemyCount += 5;
createWave();
}
}
int Wave::getEnemyCount() const {
return enemyCount;
}
The collision work correct, but when bullet touch a enemy of index for example: 5, a code always remove the enemy of last index, so I can remove each enemy only shoot to one enemy with index 5 or 1 or 7.
When you do enemyArray.erase(...) you shouldn't increment i because you will skip one element.
So you should rewrite the loop like this:
for (int i = 0; i < enemyArray.size();) {
if (player->checkShoot()) {
if ((bullet->getPositionX() >= enemyArray.at(i).getPositionX() && bullet->getPositionX() <= enemyArray.at(i).getPositionX() + 5)) {
if ((bullet->getPositionY() >= enemyArray.at(i).getPositionY() && bullet->getPositionY() <= enemyArray.at(i).getPositionY() + 5)) {
player->addScore(10);
enemyArray.erase(enemyArray.begin() + i);
continue;
}
}
}
++i;
}
Or, with a more idiomatic style:
for (auto it = enemyArray.begin(), end = enemyArray.end();it!=end;) {
if (player->checkShoot()) {
if ((bullet->getPositionX() >= it->getPositionX() && bullet->getPositionX() <= it->getPositionX() + 5)) {
if ((bullet->getPositionY() >= it->.getPositionY() && bullet->getPositionY() <= it->getPositionY() + 5)) {
player->addScore(10);
enemyArray.erase(it);
continue;
}
}
}
++it;
}
Of course, if you wan a single enemy to be removed at a time, you should break instead of continue in the loop, after having erased the element.
For completeness, you can also use std::remove_if if you want to remove all enemies touched by the bullet, it's more optimal than the 2 loops above, because it does less moving of elements when multiple elements are removed.
Related
Me and my group is making a game for our project and I keep running into this error, after some testing, it looks like it happens at the end of the main function. I have no idea how this happen as most of the code is from our teacher, we need to fix the intentional bugs placed by him and add additional functionalities.
This is the code:
#include <winuser.h>
#include <iostream>
#include <time.h>
#include <conio.h>
#include <thread>
using namespace std;
#define MAX_CAR 5
#define MAX_CAR_LENGTH 40
#define MAX_SPEED 3
POINT** X;
POINT Y;
int cnt = 0;
int MOVING;
int SPEED;
int HEIGHT_CONSOLE = 29, WIDTH_CONSOLE = 119;
bool STATE;
void FixConsoleWindow() {
HWND consoleWindow = GetConsoleWindow();
LONG_PTR style = GetWindowLongPtr(consoleWindow, GWL_STYLE);
style = style & ~(WS_MAXIMIZEBOX) & ~(WS_THICKFRAME);
SetWindowLongPtr(consoleWindow, GWL_STYLE, style);
}
void GotoXY(int x, int y) {
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
void ResetData() {
MOVING = 'D';
SPEED = 1;
Y = { 18, 19 };
if (X == NULL) {
X = new POINT * [MAX_CAR];
for (int i = 0; i < MAX_CAR; i++) {
X[i] = new POINT[MAX_CAR_LENGTH];
}
for (int i = 0; i < MAX_CAR; i++) {
int temp = rand() % (WIDTH_CONSOLE - MAX_CAR_LENGTH) + 1;
for (int j = 0; j < MAX_CAR_LENGTH; j++) {
X[i][j].x = temp + j;
X[i][j].y = 2 + 5 * i;
}
}
}
}
void DrawBoard(int x, int y, int width, int height, int curPosX = 0, int curPosY = 0) {
GotoXY(x, y);
for (int i = 1; i < width; i++) {
cout << 'X';
}
cout << 'X';
GotoXY(x, height + y);
for (int i = 1; i < width; i++) {
cout << 'X';
}
cout << 'X';
for (int i = y + 1; i < height + y; i++) {
GotoXY(x, i);
cout << 'X';
GotoXY(x + width, i);
cout << 'X';
}
GotoXY(curPosX, curPosY);
}
void StartGame() {
system("cls");
ResetData();
DrawBoard(0, 0, WIDTH_CONSOLE, HEIGHT_CONSOLE);
STATE = true;
}
void GabageCollect() {
for (int i = 0; i < MAX_CAR; i++) {
delete[] X[i];
}
delete[] X;
}
void ExitGame(HANDLE t) {
GabageCollect();
system("cls");
TerminateThread(t, 0);
}
void PauseGame(HANDLE t) {
SuspendThread(t);
}
void ProcessDeath() {
STATE = false;
GotoXY(0, HEIGHT_CONSOLE + 2);
cout << "Dead, type y to continue or any key to exit";
}
void ProcessFinish(POINT& p) {
SPEED == MAX_SPEED ? SPEED = 1 : SPEED++;
p = { 18,19 };
MOVING = 'D';
}
void DrawCars() {
for (int i = 0; i < MAX_CAR; i++) {
for (int j = 0; j < MAX_CAR_LENGTH; j++) {
GotoXY(X[i][j].x, X[i][j].y);
std::cout << '.';
}
}
}
void DrawPlayer(const POINT& p, char s) {
GotoXY(p.x, p.y);
cout << s;
}
bool IsImpact(const POINT& p) //d=Y.y p = Y
{
if (p.y == 1 || p.y == 19) return false;
for (int i = 0; i < MAX_CAR; i++)
{
for (int j = 0; j < MAX_CAR_LENGTH; j++)
{
if (p.x == X[i][j].x && p.y == X[i][j].y) return true;
}
}
return false;
}
void MoveCars(int x1, int y1)
{
for (int i = 1; i < MAX_CAR; i += 2)
{
cnt = 0;
do
{
cnt++;
for (int j = 0; j < MAX_CAR_LENGTH - 1; j++)
{
X[i][j] = X[i][j + 1];
}
X[i][MAX_CAR_LENGTH - 1].x + 1 == WIDTH_CONSOLE + x1 ? X[i][MAX_CAR_LENGTH - 1].x = 1 : X[i][MAX_CAR_LENGTH - 1].x++;
} while (cnt < SPEED);
}
for (int i = 0; i < MAX_CAR; i += 2)
{
cnt = 0;
do
{
cnt++;
for (int j = MAX_CAR_LENGTH - 1; j > 0; j--)
{
X[i][j] = X[i][j - 1];
}
X[i][0].x - 1 == 0 + x1 ? X[i][0].x = WIDTH_CONSOLE + x1 - 1 : X[i][0].x--;
} while (cnt < SPEED);
}
}
void EraseCars()
{
for (int i = 0; i < MAX_CAR; i += 2)
{
cnt = 0;
do
{
GotoXY(X[i][MAX_CAR_LENGTH - 1 - cnt].x, X[i][MAX_CAR_LENGTH - 1 - cnt].y);
cout << " ";
cnt++;
} while (cnt < SPEED);
}
for (int i = 1; i < MAX_CAR; i += 2)
{
cnt = 0;
do
{
GotoXY(X[i][0 + cnt].x, X[i][0 + cnt].y);
cout << " ";
cnt++;
} while (cnt < SPEED);
}
}
void MoveRight()
{
if (Y.x < WIDTH_CONSOLE - 1)
{
DrawPlayer(Y, ' ');
Y.x++;
DrawPlayer(Y, 'Y');
}
}
void MoveLeft()
{
if (Y.x > 1)
{
DrawPlayer(Y, ' ');
Y.x--;
DrawPlayer(Y, 'Y');
}
}
void MoveDown()
{
if (Y.y < HEIGHT_CONSOLE - 1)
{
DrawPlayer(Y, ' ');
Y.y++;
DrawPlayer(Y, 'Y');
}
}
void MoveUp()
{
if (Y.y > 1)
{
DrawPlayer(Y, ' ');
Y.y--;
DrawPlayer(Y, 'Y');
}
}
void SubThread()
{
while (1)
{
if (STATE)
{
switch (MOVING)
{
case 'A':
MoveLeft();
break;
case 'D':
MoveRight();
break;
case'W':
MoveUp();
break;
case'S':
MoveDown();
break;
}
MOVING = ' ';
EraseCars();
MoveCars(0, 0);
DrawCars();
if (IsImpact(Y))
{
ProcessDeath();
}
if (Y.y == 1)
{
ProcessFinish(Y);
Sleep(50);
}
}
}
}
void main()
{
int temp;
FixConsoleWindow();
srand(time(NULL));
StartGame();
thread t1(SubThread);
while (1)
{
temp = toupper(_getch());
if (STATE == 1)
{
EraseCars();
if (temp == 27)
{
ExitGame(t1.native_handle());
break;
}
else if (temp == 'P')
{
PauseGame(t1.native_handle());
temp = toupper(_getch());
if (temp == 'B')
ResumeThread((HANDLE)t1.native_handle());
}
else
{
if (temp == 'D' || temp == 'A' || temp == 'W' || temp == 'S')
{
MOVING = temp;
}
}
}
else
{
if (temp == 'Y') StartGame();
else
{
ExitGame(t1.native_handle());
break;
}
}
}
}
And this is the image of the error: https://imgur.com/PGJJX2w
Basically, this is a crossing road game, every time you go to the top, it saves the location and you cannot go that location again (still working on this), game finish when you run into the cars (lines of dots as of the moment). Thanks in advance
You created a std::thread object here:
thread t1(SubThread);
but you didn't call join() nor detach() for that.
This causes that std::terminate() is called (the program aborts) when the object is destructed.
Call t1.join() if you want to wait until the thread ends or t1.detach() if you want to let the thread run freely before returning from the main() function.
Another option is using CreateThread() directly instead of std::thread to create threads. This may be better because you are using t1.native_handle() for operations on the thread.
This problem which is similar to another that I solved here is giving me a wrong answer even though the algorithm works on the sample case.I have initialized all the variables this time and it works on a modified version of my previous algorithm.
#include <iostream>
int main() {
int n;
std::cin >> n;
int arr[n];
for (int i = 0; i <n ;++i) {
std::cin >> arr[i];
}
int four_count = 0, two_count = 0, three_long=0, one_long = 0 , max1_long = 0 ,max3_long = 0,a_depth = 0,max_depth = 0;
for (int i = 0; i < n; ++i) {
if (arr[i] == 3) {
if (arr[i+1] == 1) {
++a_depth;
if (a_depth > max_depth) {
max_depth = a_depth;
}
}
++four_count;
three_long += 2;
}
if (arr[i] == 1) {
if (arr[i+1] == 3) {
++a_depth;
if (a_depth > max_depth) {
max_depth = a_depth;
}
}
++two_count;
one_long += 2 ;
}
if (arr[i] == 2) {
if (arr[i+1] == 4 && i < n-1) {
--a_depth;
}
--two_count;
}
if (arr[i] == 4) {
if (arr[i+1] == 2 && i < n-1){
--a_depth;
}
--four_count;
}
if (four_count == 0 && two_count == 0) {
if (three_long >= one_long) {
if (three_long > max3_long) {
max3_long = three_long+one_long;
}
three_long = 0;
one_long = 0;
}
else {
if (one_long > max1_long) {
max1_long = one_long+three_long;
}
one_long = 0;
three_long = 0;
}
}
}
std::cout << max_depth*2 << " " << max1_long << " " << max3_long;
std::cout << "\n";
return 0;
}
Here is a link to the problem:
https://www.codechef.com/ZCOPRAC/problems/ZCO12003
In the below code:
for (int i = 0; i < n; ++i) {
if (arr[i] == 3) {
if (arr[i+1] == 1) {
when i reaches n-1, arr[i+1] becomes arr[n] resulting in an out-of-bounds memory access which will lead to undefined behaviour.
Let's say n is equal to 5. That means the array arr has the maximum index 4, because the first one is 0.
In your loop
for (int i = 0; i < n; ++i)
{ if (arr[i] == 3) {
if (arr[i+1] == 1) {
at some point i becomes n-1, so i == 4, then you try arr[i+1] meaning arr[5], which is out of bound.
Note that in the comment to P.Ws post, you tried if (arr[i+1] == 1 && i < n-1) to fix this. That won't work because there still is an arr[i+1] being executed. You could fix this by using
if(i < n-1) {
if(arr[i+1]) {
but that would mean an even deeper nesting of your ifs. You should probably rethink your approach to the given problem.
Edit: Are you sure you mean ++i and not i++?
I am trying to do the Knight's Tour using dynamic arrays because the user will be able to implement their own board size, and where they want to start the knight at in the board.
However, before I changed everything to dynamic arrays, I was able to perform my code just find using static arrays, but now that I switched to dynamic arrays whenever my code executes, I get a memory leak I believe and the program crashes. I was wondering if my deconstructor is not working properly? Or if there is a different way I have to delete the dynamic array?
I am also wondering if there is a way to make this code a little more efficient, more exactly make the Move() function a little more efficient. Thanks.
#include <iostream>
#include <iomanip>
#include "stdafx.h"
using namespace std;
class Knight
{
private:
int Tracker = 1;
int BoardSize;
int **Board = new int*[BoardSize];
public:
Knight(int s)
{
BoardSize = s;
for (int i = 0; i <= s -1; i++)
{
Board[i] = new int[s];
}
for (int i = 0; i <= s - 1; i++)
{
for (int j = 0; j <= s - 1; j++)
{
Board[i][j] = 0;
}
}
}
~Knight()
{
for (int i = 0; i <= BoardSize - 1; i++)
{
delete[] Board[i];
}
delete[] Board;
}
void MarkUp(int &val)
{
val = Tracker;
Tracker++;
}
void MarkDown(int &val)
{
val = 0;
Tracker--;
}
bool PossibleMove(int &val)
{
if (val == 0)
return 1;
else
return 0;
}
void Display()
{
for (int k = 0; k < (BoardSize * 5) + 1; k++)
{
cout << "-";
}
cout << endl;
for (int i = 0; i <= BoardSize - 1; i++)
{
cout << "| ";
for (int j = 0; j <= BoardSize - 1; j++)
{
cout << setw(2) << setfill('0') << Board[i][j] << " | ";
}
cout << endl;
for (int k = 0; k < (BoardSize * 5) + 1; k++)
{
cout << "-";
}
cout << endl;
}
cout << endl << endl;
}
bool Move(int x, int y)
{
if (Tracker > (BoardSize * BoardSize))
{
return true;
}
if (PossibleMove(Board[x][y])) {
if ((x - 2 >= 0) && (y + 1 <= (BoardSize - 1)))
{
MarkUp(Board[x][y]);
if (Move(x - 2, y + 1))
{
return true;
}
else
{
MarkDown(Board[x][y]);
}
}
if ((x - 2 >= 0) && (y - 1 >= 0))
{
MarkUp(Board[x][y]);
if (Move(x - 2, y - 1))
{
return true;
}
else
{
MarkDown(Board[x][y]);
}
}
if ((x - 1 >= 0) && (y + 2 <= (BoardSize - 1)))
{
MarkUp(Board[x][y]);
if (Move(x - 1, y + 2))
{
return true;
}
else
{
MarkDown(Board[x][y]);
}
}
if ((x - 1 >= 0) && (y - 2 >= 0))
{
MarkUp(Board[x][y]);
if (Move(x - 1, y - 2))
{
return true;
}
else
{
MarkDown(Board[x][y]);
}
}
if ((x + 2 <= (BoardSize - 1)) && (y + 1 <= (BoardSize - 1)))
{
MarkUp(Board[x][y]);
if (Move(x + 2, y + 1))
{
return true;
}
else
{
MarkDown(Board[x][y]);
}
}
if ((x + 2 <= (BoardSize - 1)) && (y - 1 >= 0))
{
MarkUp(Board[x][y]);
if (Move(x + 2, y - 1))
{
return true;
}
else
{
MarkDown(Board[x][y]);
}
}
if ((x + 1 <= (BoardSize - 1)) && (y + 2 <= (BoardSize - 1)))
{
MarkUp(Board[x][y]);
if (Move(x + 1, y + 2))
{
return true;
}
else
{
MarkDown(Board[x][y]);
}
}
if ((x + 1 <= (BoardSize - 1)) && (y - 2 >= 0))
{
MarkUp(Board[x][y]);
if (Move(x + 1, y - 2))
{
return true;
}
else
{
MarkDown(Board[x][y]);
}
}
}
return false;
}
};
int main()
{
int size = 0;
int Row, Col;
int opt = 0;
do
{
cout << "Welcome to Knights Tour!" << endl;
cout << "1) Start the Tour." << endl;
cout << "2) Quit." << endl;
cin >> opt;
switch (opt)
{
case 1:
{
cout << "Enter board size:" << endl;
cin >> size;
Knight K1(size);
cout << "Enter Row:" << endl;
cin >> Row;
cout << "Enter Column: " << endl;
cin >> Col;
if (K1.Move(Row, Col))
{
cout << "\nOperation was Successful." << endl;
cout << "Possible Solution:" << endl;
K1.Display();
}
else
{
cout << "\nThat is not Possible." << endl;
}
cout << endl;
break;
}
case 2:
{
exit(0);
break;
}
default:
{
cout << "Not a Valid Option." << endl;
cout << "Try Again Please." << endl;
cout << endl;
break;
}
}
} while (opt != 2);
return 0;
}
This code does not work as you think it does:
int BoardSize;
int **Board = new int*[BoardSize];
The value of BoardSize is going to be whatever happens to be in the memory that gets allocated for it, so the new is going to try to allocate an unknowable size array.
Don't use hand coded dynamic arrays for this. Use std::vector; That's what it's for. In real life production code, you should almost never ever use dynamically allocated arrays. You'll use one of the standard containers.
As noted in the comments by multiple people, memory leaks do not cause crashes (generally).
The issue is that inside the constructor you assign values to the Board array elements. However, you never allocate memory for the Board array itself. I.e. when you do Board[i] = new int[s];, Board points to some random address. This is because the line int **Board = new int*[BoardSize]; is not executed before the constructor starts.
So the following should work:
class Knight {
private:
int BoardSize;
int **Board;
public:
Knight (int s) {
BoardSize = s;
Board = new int*[BoardSize];
// Remainder of code
}
};
However, I really suggest you use std::vector for this instead. Then you won't have to deal with memory (de)allocation at all. That could look as concise as the following:
#include <vector>
class Knight {
private:
int BoardSize;
std::vector<std::vector<int>> Board;
public:
Knight (int s) : BoardSize(s), Board(s, std::vector<int>(s, 0)) { }
};
Note that I initialized the class members directory in the member initializer list.
My program is suppose to count how many times the data in my array changed from increase to decrease or vice versa. For example: {1,2,3,4,3,4}
changes twice as the first four elements are increasing then decrease o 3 (causing one change) and then increase back to four causing a second change.
The idea in my code was that every time greater or decrease changed to false it would count when it happened but I cannot get it to work.
Any help is greatly appreciated as I am really struggling with this!
unsigned count = 0;
bool greater = true;
bool decrease = true;
for (unsigned i = 0; i < elements; i++){
if (a[i + 1] > a[i]){
greater = true;
}
else
greater = false;
count++;
}
for (unsigned i = 0; i < elements; i++){
if (a[i + 1] < a[i]){
decrease = true;
}
else
decrease = false;
count++;
}
return count;
Your logic is wrong
you may do something like
enum class EDirection { none, decreasing, increasing};
std::size_t count_direction_changes(const std::vector<int>& v)
{
std::size_t res = 0;
EDirection direction = EDirection::none;
for (std::size_t i = 1; i != v.size(); ++i) {
const int diff = v[i] - v[i - 1];
switch (direction)
{
case EDirection::none: {
if (diff == 0) {
break;
}
direction = (diff > 0) ? EDirection::increasing : EDirection::decreasing;
break;
}
case EDirection::increasing: {
if (diff < 0) {
++res;
direction = EDirection::decreasing;
}
break;
}
case EDirection::decreasing: {
if (diff > 0) {
++res;
direction = EDirection::increasing;
}
break;
}
}
}
return res;
}
Demo
You must change your loops. First of all you should stop the loop at size-1. Because you are comparing with next element and you can go out of bounds if your for is running until elements instead of elements-1.
Furthermore, you have a logic issue. If you are using a boolean variable as flag, you should check if it's true or not before increasing your counter. And in case you increments your counter you must reset that flag. Something similar to down loop should work. Maybe there is some little mistake because I don't have anythin to test it now. But it should be something similar to this.
for (unsigned i = 0; i < elements-1; i++){
if (a[i + 1] > a[i]){
greater = true;
}
else{
greater = false;
}
if(greater){
count++;
greater = false;
}
}
This is a lot like Jarod42's, but seeing as I've already coded it will throw it out there. BTW, I use the slightly awkward v[n] < v[n - 1] so it's only necessary to implement operator< to apply the algo to a user-defined type (i.e. not operator> as well).
#include <iostream>
#include <vector>
template <typename T>
size_t changes(const std::vector<T>& v)
{
if (v.size() <= 2) return 0;
size_t count = 0;
enum { Increasing, Decreasing, Flat } last;
last = v[0] < v[1] ? Increasing : v[1] < v[0] ? Decreasing : Flat;
for (size_t i = 2; i < v.size(); ++i)
if (v[i - 1] < v[i])
{
if (last == Decreasing) ++count;
last = Increasing;
}
else if (v[i] < v[i - 1])
{
if (last == Increasing) ++count;
last = Decreasing;
}
return count;
}
int main()
{
std::cout << changes<int>({ 1, 3, 5, 4, 6 }) << '\n';
std::cout << changes<int>({ 3, 3, 5, 4, 6 }) << '\n';
std::cout << changes<int>({ 4, 3, 5, 4, 2, 2, 1 }) << '\n';
}
See it run here.
Here is another approach, similar to Tony's and Jarod's:
#include <vector>
#include <cassert>
#include <iostream>
size_t countTrendChanges(const std::vector<int>& a) {
if (a.size() < 3)
return 0;
int trend = 0;
size_t count = 0;
for (size_t i = 1; i != a.size(); ++i) {
int new_trend = (a[i-1] < a[i]) - (a[i] < a[i-1]);
if (new_trend == 0)
continue;
if (trend != 0 && new_trend != trend)
count++;
trend = new_trend;
}
return count;
}
int main() {
assert(countTrendChanges({}) == 0);
assert(countTrendChanges({1}) == 0);
assert(countTrendChanges({3,2,1}) == 0);
assert(countTrendChanges({1,2,3}) == 0);
assert(countTrendChanges({1,2,2,3}) == 0);
assert(countTrendChanges({3,2,1,2,3}) == 1);
assert(countTrendChanges({1,2,3,2}) == 1);
assert(countTrendChanges({2,1,1,2}) == 1);
assert(countTrendChanges({1,2,2,1}) == 1);
assert(countTrendChanges({1,2,3,4,3,4}) == 2);
}
I saw Conway's Game of Life and decided to make my own.
I have a bool array to represent the world, but the edges (Top and bottom) are acting weird, random cells becomes live.
In this code, it does not print the bottom and top of the world, but this is a bad solution.
The world "wraps" at the right and the left, causing even more problems, but that is for another time.
#include <iostream>
const int height = 20;
const int width = 20;
bool now_world[height][width];
bool then_world[height][width];
void clear_world();
void place_random_live_cells();
void then_world_initialization();
void print_world();
void generation_pass();
void update_worlds();
int main(int argc, const char * argv[])
{
using namespace std;
srand((unsigned)time(NULL));
int timer = 0;
int generation = 0;
clear_world();
place_random_live_cells();
then_world_initialization();
bool running = true;
while (running) {
if (timer == 50000000) {
cout << "Generation #" << generation << endl;
print_world();
generation_pass();
update_worlds();
++generation;
timer = 0;
}
++timer;
}//While (running) ends here
return 0;
}
void place_random_live_cells()
{
int percent = 30;
int max_live_cells = ((height * width) / 100) * percent;
int current_live_cells = 0;
while (current_live_cells < max_live_cells) {
int ycoords = 0 + (rand() % (height + 1));
int xcoords = 0 + (rand() % (width + 1));
if (now_world[ycoords][xcoords] == false) {
now_world[ycoords][xcoords] = true;
} else {
current_live_cells--;
}
++current_live_cells;
}
}
//A generation pass and cells die and some cells come to life
void generation_pass()
{
using namespace std;
int neighbours = 0;
for (int iii = 0; iii < height; iii++) {
for (int jjj = 0; jjj < width; jjj++) {
//Count neighbouring cells that are alive
if (now_world[iii+1][jjj+1] == true) {
++neighbours;
}
if (now_world[iii+1][jjj ] == true) {
++neighbours;
}
if (now_world[iii+1][jjj-1] == true) {
++neighbours;
}
if (now_world[iii ][jjj+1] == true) {
++neighbours;
}
if (now_world[iii ][jjj-1] == true) {
++neighbours;
}
if (now_world[iii-1][jjj+1] == true) {
++neighbours;
}
if (now_world[iii-1][jjj ] == true) {
++neighbours;
}
if (now_world[iii-1][jjj-1] == true) {
++neighbours;
}
//Apply rules to the cells
//Dead cells with three live neighbours becomes alive
if (then_world[iii][jjj] == false && neighbours == 3) {
then_world[iii][jjj] = true;
}
//Alive with fewer than two, they die
if (then_world[iii][jjj] == true && neighbours < 2) {
then_world[iii][jjj] = false;
}
//Alive with 2 or three live neighbours live on unchanged
if (then_world[iii][jjj] == true && neighbours == 2) {
then_world[iii][jjj] = true;
}
if (then_world[iii][jjj] == true && neighbours == 3) {
then_world[iii][jjj] = true;
}
//Alive with more than three, they die
if (then_world[iii][jjj] == true && neighbours > 3) {
then_world[iii][jjj] = false;
}
//Dead cells without exactly three live neighbours remain dead
//Reset neighbour value to zero
neighbours = false;
}
}
}
//Make next generation identical to current
//This is only called once
void then_world_initialization()
{
for (int iii = 0; iii < height; iii++) {
for (int jjj = 0; jjj < width; jjj++) {
then_world[iii][jjj] = now_world[iii][jjj];
}
}
}
//Make the next generation be today
//This is called every generation
void update_worlds()
{
for (int iii = 0; iii < height; iii++) {
for (int jjj = 0; jjj < width; jjj++) {
now_world[iii][jjj] = then_world[iii][jjj];
}
}
}
//Set all cells to dead
void clear_world()
{
for (long iii = 0; iii < height; iii++) {
for (long jjj = 0; jjj < width; jjj++) {
now_world[iii][jjj] = false;
then_world[iii][jjj] = false;
}
}
}
//Print world
void print_world()
{
using namespace std;
char live = 'X';
char dead = '.';
for (long iii = height; iii > 0; iii--) {
for (long jjj = width; jjj > 0; jjj--) {
if (iii != 0 && iii != height) {
if (now_world[iii][jjj]) {
cout << live;
} else {
cout << dead;
}
cout << " ";
}
}
cout << endl;
}
cout << endl;
}
Having done this for a course I taught in the past, the most common issue I always see people having is going outside the bounds of the array they're using.
If you look at the if statements in your nested for loop, I think you'll find some issues. For instance, in this case, what happens when iii equals (height-1) or jjj equals (width-1)?
for (int iii = 0; iii < height; iii++) {
for (int jjj = 0; jjj < width; jjj++) {
//Count neighbouring cells that are alive
if (now_world[iii+1][jjj+1] == true) {
++neighbours;
You're going outside the bounds of your array and so your results will be undefined. You may get segfaults, but you may just also get spurious data. C++ doesn't enforce you staying within the bounds of the array you define.
Make sure you also handle cases like this:
if (now_world[iii-1][jjj+1] == true) {
++neighbours;
}
What if iii equals zero?
Hope that helps.
You're trying to access out-of-boundary indexes in your array.
I'm not sure what behaviour you expect, but an easy way is to not calculate updates for cells on the edges.
So in generation_pass the loops should go from 1 till height-1.