Conway's game of life: checking neighbours not working properly (c++) - c++

I've been trying to figure out the problem behind this for a few days. I think it's counting the neighbours incorrectly because when I print the counts, the numbers are mostly 1s and 2s and my output board is completely blank. X ('X') means alive and ' ' means dead.
void NextGen(char lifeBoard[][MAX_ARRAY_SIZE], int numRowsInBoard, int numColsInBoard) {
char nexGenBoard[MAX_ARRAY_SIZE][MAX_ARRAY_SIZE];
// initialize nexGenBoard to blanks spaces
for(int i = 0; i < numRowsInBoard; i++) {
for(int j = 0; j < numColsInBoard; j++) {
nexGenBoard[i][j] = {' '};
}
}
// start from i = 1 and j = 1 to ignore the edge of the board
for(int i = 1; i < numRowsInBoard-1; i++) {
for(int j = 1; j < numColsInBoard-1; j++) {
int count = 0;
for(int y = -1; y < 2; y++) {
for(int x = -1; x < 2; x++) {
if(!(x == 0 || y == 0)) {
if(lifeBoard[i+y][j+x] == X) //X is a global constant of 'X'.
{
count++;
}
}
}
}
if(lifeBoard[i][j] == X) {
if(count == 2 || count == 3) {
nexGenBoard[i][j] = X;
}
}
else if(lifeBoard[i][j] == ' ') {
if(count == 3) {
nexGenBoard[i][j] = X;
}
}
}
}
for(int i = 0; i < numRowsInBoard; i++) {
for(int j = 0; j < numColsInBoard; j++) {
lifeBoard[i][j] = nexGenBoard[i][j];
}
}
}

Your check during counting (!(x == 0 || y == 0)) is wrong. This will not check the square if either x or y is zero. You want to not count if both x and y are zero.
if (!(x == 0 && y == 0))
or
if (x != 0 || y != 0)

Related

Vector subscription out of range error c++

I am trying to create a simulation of conway's game of life.
I keep getting a "vector subscript out of range" error after about 300 generation and I don't understand the reason. From what I could gather it's caused by using an invalid index. The most likely section is the first part of the draw function where I find empty rows and replace them with "\n" to save time.
I've started learning to code not too long ago so I may be making baby mistakes.
Edit: visual studio point the error after the third for loop in the frame function, on if (emptyRows[m] == i)
Here's the full code :
#include <array>
#include <time.h>
#include <vector>
const int WIDTH = 150;
const int HEIGHT = 50;
bool table[WIDTH][HEIGHT];
bool tableNew[WIDTH][HEIGHT];
std::string buffer;
int total;
int counter = 0;
std::vector<int> emptyRows;
int numberOfNeighbours(int Y, int X) {
if (X == 0 || Y == 0 || X == WIDTH || Y == HEIGHT)
return 2;
total = 0;
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (table[X + j][Y + i] == true)
total++;
}
}
total -= table[X][Y];
return total;
}
void draw() {
srand((int)time(0));
int m = 0;
bool check = 0;
for (int i = 0; i < HEIGHT; i++) {
for (int j = 0; j < WIDTH; j++) {
if (table[j][i] == 1)
check = 1;
}
if (check == 0)
emptyRows.push_back(i);
else
check = 0;
}
for (int i = 0; i < HEIGHT; i++) {
if (emptyRows.size() >= 1) {
if (emptyRows[m] == i) {
buffer.append("\n");
m++;
continue;
}
}
for (int j = 0; j < WIDTH; j++) {
if (table[j][i] == 1) buffer.push_back('#');
else buffer.push_back(' ');
}
buffer.append("\n");
}
std::cout << buffer;
std::cout << std::endl << "Generazione numero:" << counter;
emptyRows.erase(emptyRows.begin(), emptyRows.end());
buffer.erase(buffer.begin(), buffer.end());
m = 0;
}
void reset() {
for (int i = 0; i < HEIGHT; i++) {
for (int j = 0; j < WIDTH; j++) {
table[j][i] = tableNew[j][i];
}
}
}
void logic() {
for (int i = 0; i < HEIGHT; i++) {
for (int j = 0; j < WIDTH; j++) {
int k = numberOfNeighbours(i, j);
if (table[j][i] == 0 && k == 3)
tableNew[j][i] = 1;
else if (table[j][i] == 1 && k != 2 && k != 3)
tableNew[j][i] = 0;
else
tableNew[j][i] = table[j][i];
}
}
}
int main(){
for (int i = 0; i < HEIGHT; i++) {
for (int j = 0; j < WIDTH; j++) {
if ((rand() % 2) == 1)
table[j][i] = 1;
}
}
while (true) {
counter++;
draw();
logic();
reset();
system("cls");
}
return 0;
}

Null characters randomly added to string C++

I have written a simple battleship game in C++. After several iterations of the game, one of the strings in a "Player" object is changed. This change is several null characters are added to the end of the string. Otherwise the rest of the object is untouched. For example if the player type is "cpu", the player type switches to "cpu\0\0\0\0\0\0\0\0". I believe the line of code causing the problem is:
currPlayer->getStrategy().getNextAttack(nextPlayer->getBoard(1));
Here is the code for getNextAttack():
int Strategy::getNextAttack(Board enemyBoard) {
//clear prob board
for(int i = 0; i < 100; i++) {
probBoard[i] = 0;
}
//reset largest ship
largestShip = 0;
//assign largest ship
for(int i = 0; i < 100; i++) {
Ship currShip = enemyBoard.getShipByCoord(i);
if(!currShip.isSunk()) { //if ship is still afloat
if(currShip.getSize() > largestShip) { largestShip = currShip.getSize(); } //reassign largest ship on board
}
}
//assign base prob
std::vector<int> allPossible;
//for all horiz coords
for(int i = 0; i < 10; i++) {
for(int j = 0; j < (10 - largestShip +1); j++) {
for(int k = 0; k < (largestShip); k++) {
if(!enemyBoard.beenHit((i*10) + j + k) || (enemyBoard.beenHit((i*10) + j + k) && !enemyBoard.getShipByCoord((i*10) + j + k).isSunk())) { //if not hit or if hit but contains a ship that is not sunk
allPossible.push_back((i*10) + j + k);
}
else {
for(int m = 0; m < k; m++) {
allPossible.pop_back(); //should delete last element
}
break;
}
}
//for all vert coords
for(int z = 0; z < (largestShip); z++) {
if(!enemyBoard.beenHit(((j+z)*10) + i)) {
allPossible.push_back(((j+z)*10) + i);
}
else {
for(int m = 0; m < z; m++) {
allPossible.pop_back(); //should delete last element
}
break;
}
}
}
}
for(int p = 0; p < allPossible.size(); p++) {
probBoard[allPossible[p]] += 1;
}
//add improvements based on hits
for(int i = 0; i < 10; i++) {
for(int k = 0; k < 10; k++) {
int currCoord = (i*10) + k;
int leftCoord = (i*10) + k-1;
int rightCoord = (i*10) + k+1;
int upCoord = ((i-1)*10) + k;
int downCoord = ((i+1)*10) + k;
if(enemyBoard.beenHit(currCoord) && (enemyBoard.getShipByCoord(currCoord).getName() != "") && !enemyBoard.getShipByCoord(currCoord).isSunk()) { //currCoord is a coordinate that has been hit, contains a ship and is not sunk
if((enemyBoard.beenHit(leftCoord) || enemyBoard.beenHit(rightCoord)) && (enemyBoard.getShipByCoord(leftCoord) == enemyBoard.getShipByCoord(currCoord) || enemyBoard.getShipByCoord(rightCoord) == enemyBoard.getShipByCoord(currCoord))) { //if space to left or right is hit and the same ship
//increment only the left and right
if(!enemyBoard.getShipByCoord(currCoord).isSunk()) { //ship cannot be sunk as well
probBoard[leftCoord] += 25;
probBoard[rightCoord] += 25;
}
}
else if((enemyBoard.beenHit(upCoord) || enemyBoard.beenHit(downCoord)) && (enemyBoard.getShipByCoord(upCoord) == enemyBoard.getShipByCoord(currCoord) || enemyBoard.getShipByCoord(downCoord) == enemyBoard.getShipByCoord(currCoord))) { //if space on top or bottom is hit and the same ship and not sunk
//increment only the top and bottom
if(!enemyBoard.getShipByCoord(currCoord).isSunk()) { //ship cannot be sunk as well
probBoard[upCoord] += 25;
probBoard[downCoord] += 25;
}
}
//if no direct spaces in any direction to hit coord, increment top, bot, left, and right equally
else {
probBoard[upCoord] += 20;
probBoard[downCoord] += 20;
probBoard[leftCoord] += 20;
probBoard[rightCoord] += 20;
}
}
}
}
//marks odds at 0 if already fired upon
for(int n = 0; n < 100; n++) {
if(enemyBoard.beenHit(n)) {
probBoard[n] = 0;
}
}
//find next best attack coord based on prob board
int highestValue = 0;
std::vector<int> highestSpaces;
for(int j = 0; j < 100; j++) {
if(probBoard[j] > highestValue) { highestValue = probBoard[j]; }
}
for(int r = 0; r < 100; r++) {
if(probBoard[r] == highestValue) {
highestSpaces.push_back(r);
}
}
srand(static_cast<unsigned int>(time(NULL)));
int randNum = rand() % highestSpaces.size();
return highestSpaces[randNum];
}
Thank you for reading and any help!
This looks like it will go out of the array bounds at the edges when the row or column is 0 or 9:
probBoard[upCoord] += 20;
probBoard[downCoord] += 20;
probBoard[leftCoord] += 20;
probBoard[rightCoord] += 20;

How to reset X back into its original position within the arrays?

I have been making a maze game over the past few weeks and have finished coding it 3 days ago. I have been testing the game for any bugs, and everything seemed alright, however one major problem I have been having is that the game crashes if I am wanting to play the same level in one run of the game. For example, I play level 1 and 2, and if I select either of them again on the main menu, the game gets a blank screen and crashes.
I have sourced the bug into three of my functions, which are the following:
void position(int lvl) {
int x, y;
if (lvl == 1) {
x = startingPointX(lvl, y);
lvl1[x][y] = me;
}
if (lvl == 2) {
x = startingPointX(lvl, y);
lvl2[x][y] = me;
}
if (lvl == 3) {
x = startingPointX(lvl, y);
lvl3[x][y] = me;
}
if (lvl == 4) {
x = startingPointX(lvl, y);
lvl4[x][y] = me;
}
if (lvl == 5) {
x = startingPointX(lvl, y);
lvl5[x][y] = me;
}
if (lvl == 6) {
x = startingPointX(lvl, y);
lvl6[x][y] = me;
}
}
Here is the second function:
int positionFinder(int lvl, int &y) {
int xCoord;
if (lvl == 1) {
/*This is for level 1*/
for (int i = 0; i != 20; ++i) {
for (int j = 0; j != 20; ++j) {
if (lvl1[i][j] == '#') {
xCoord = i;
y = j;
return xCoord;
}
}
}
}
if (lvl == 2) {
/*This is for level 2*/
for (int i = 0; i != 20; ++i) {
for (int j = 0; j != 20; ++j) {
if (lvl2[i][j] == '#') {
xCoord = i;
y = j;
return xCoord;
}
}
}
}
if (lvl == 3) {
/*This is for level 3*/
for (int i = 0; i != 20; ++i) {
for (int j = 0; j != 20; ++j) {
if (lvl3[i][j] == '#') {
xCoord = i;
y = j;
return xCoord;
}
}
}
}
if (lvl == 4) {
/*This is for the solution of level 1*/
for (int i = 0; i != 20; ++i) {
for (int j = 0; j != 20; ++j) {
if (lvl4[i][j] == '#') {
xCoord = i;
y = j;
return xCoord;
}
}
}
}
if (lvl == 5) {
/*This is for the solution of level 2*/
for (int i = 0; i != 20; ++i) {
for (int j = 0; j != 20; ++j) {
if (lvl5[i][j] == '#') {
xCoord = i;
y = j;
return xCoord;
}
}
}
}
if (lvl == 6) {
/*This is for the solution of level 3*/
for (int i = 0; i != 20; ++i) {
for (int j = 0; j != 20; ++j) {
if (lvl6[i][j] == '#') {
xCoord = i;
y = j;
return xCoord;
}
}
}
}
return 0;
}
The third function is this:
int startingPointX(int lvl, int &y) {
int xCoord;
if (lvl == 1) {
/*This is for level 1*/
for (int i = 0; i != 20; ++i) {
for (int j = 0; j != 20; ++j) {
if (lvl1[i][j] == 'X') {
xCoord = i;
y = j;
return xCoord;
}
}
}
}
if (lvl == 2) {
/*This is for level 2*/
for (int i = 0; i != 20; ++i) {
for (int j = 0; j != 20; ++j) {
if (lvl2[i][j] == 'X') {
xCoord = i;
y = j;
return xCoord;
}
}
}
}
if (lvl == 3) {
/*This is for level 3*/
for (int i = 0; i != 20; ++i) {
for (int j = 0; j != 20; ++j) {
if (lvl3[i][j] == 'X') {
xCoord = i;
y = j;
return xCoord;
}
}
}
}
if (lvl == 4) {
/*This is for the solution of level 1*/
for (int i = 0; i != 20; ++i) {
for (int j = 0; j != 20; ++j) {
if (lvl4[i][j] == 'X') {
xCoord = i;
y = j;
return xCoord;
}
}
}
}
if (lvl == 5) {
/*This is for the solution of level 2*/
for (int i = 0; i != 20; ++i) {
for (int j = 0; j != 20; ++j) {
if (lvl5[i][j] == 'X') {
xCoord = i;
y = j;
return xCoord;
}
}
}
}
if (lvl == 6) {
/*This is for the solution of level 3*/
for (int i = 0; i != 20; ++i) {
for (int j = 0; j != 20; ++j) {
if (lvl6[i][j] == 'X') {
xCoord = i;
y = j;
return xCoord;
}
}
}
}
return 0;
}
The reason for the crash is that when the level runs it searches for X in int startingPointX, however then in void position the game searches for me, which is the '#', therefore if i start the second level, there will be no more 'X' in the level. The function int startingPointX is returning 0 which won't set the y, giving the y a random value. Thus, the line lvl1[x][y]; in void position will make the game will do random things due to y having a random value, which is likely out of range, resulting in a crash.
I have tried quite a few ways to change how the functions work, but every time it still ends up crashing. Help would be appreciated, thanks
Here is the full code to compile and run:
https://drive.google.com/open?id=0B2lLG0MNZMxdT3kteTBtR0puWlE
I used Windows Visual Studio 2015
I've come up with multiple potential solutions you can try implementing:
My first thought was to hardcode the starting position of me when each level is called instead of searching for the 'X'. The way you've coded your application, this also requires that when you complete the level, you change the current position of me back to a blank space, or there will still be an # at the end when the level is called again.
Another quick solution would be to store the starting position coordinates and setting that stored coordinate back to 'X' when you complete a level, once again changing the # back to a blank space.
Have you tried making each level a const character array, and copying them into another char array, such as 'CurrentLevel'?
You can achieve this using memcpy, for example:
const char lvl1[20][20] = (your array);
char currentLevel[20][20] = {0}; //all initialised to 0
Later in your code when you want to create the desired level:
//Copy the contents of lvl1 into currentLevel, up to the size of the array
memcpy(currentLevel, lvl1, sizeof(currentLvel));
Using this approach, you are able to recreate each level, including the 'X'
You will have to make changes to your code to accommodate this solution, however by referring to currentLevel instead of levels 1 - 6.

Switching letters in words C++

#include <iostream>
#include <cstring>
using namespace std;
int main() {
char main[10000] = {0};
cin.getline(main, 10000);
char clone [10000] = {0};
int n;
cin >> n;
int counter = 0;
int counter2 = 0;
for (int z = 0 ; z < strlen(main); z++) {
if (main[z] == '.' || main[z] == ',' || main[z] == ' ' || main[z] =='"' ||
main[z] == '!' || main[z] == '?' || main [z] == ';')
counter2++;
}
if (counter2 == 0) {
if (strlen(main) < n) {
n = n % strlen(main);
}
int b = strlen(main);
for (int x = b - n; x < b ; x++) {
cout << main[x];
}
for (int y = 0; y < x - n; y++) {
cout << main[y];
}
}
for (int i = 0; i < strlen(main); i++) {
clone[counter] = main[i];
if(main[i] == '.' || main[i] == ',' || main[i] == ' ' || main[i] =='"' ||
main[i] == '!' || main[i] == '?' || main [i] == ';') {
int a = strlen(clone);
if (counter < n) {
n = n % counter;
}
for (int x = a - n - 1; x < a - 1; x++) {
cout << clone[x];
}
for (int y = 0; y < x - n; y++) {
cout << clone[y];
}
cout << main[i];
counter = 0;
for (int z = 0; z < a; z++) {
clone[z] = '\0';
}
}
else {
counter++;
}
}
return 0;
}
I'm working on a project that switches letters in words. For example the word funny when n = 3 will output nnyfu. It just moves all letters n-times. However when I try to do this with a long sentence containing a character different than a letter and follow it with another char of the same type (for example a coma followed by space) the program seems to crash. I'm wondering if anyone can help me with this because I've been pulling my hair out all day long. Also it mustn't be necessary for an input with a couple of words to end with a char different than a letter but I can't seem to figure it out too (for example inputting "Hello my friends" and n = 3 it will output "lloHe ym).

Puzzle related to sorting a 2-D array in ascending order

A randomly generated 4x4 2-D array is given to the user, of which one element is definitely 0. Considering 0 to be an empty location, the user will have to exchange the remaining 15 elements with 0 repeatedly until they get the array in ascending order, with 0 as the last element.
At this point, they're allowed to exchange any element with 0.
But how do I modify this code to ensure that are only able to exchange those elements with 0 that are adjacent to it (either above, below or beside it) ?
#include<iostream>
#include<stdlib.h>
#include<time.h>
using namespace std;
int check_asc(int a[][4])
{
int i, j, previous = a[0][0];
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
if(i == 3 && j == 3)
{
if (a[i][j] == 0)
return 1;
}
else if (a[i][j] < previous)
{
return 0;
}
previous = a[i][j];
}
}
return 1;
}
void swap(int a[][4], int &xpos, int &ypos)
{
int arr, temp;
cout << "\n\nEnter number to be swapped with 0: ";
cin >> arr;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (a[i][j] == arr)
{
temp = a[xpos][ypos];
a[xpos][ypos] = a[i][j];
a[i][j] = temp;
xpos = i;
ypos = j;
return;
}
}
}
}
int check_rep(int a[][4], int assign)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (assign == a[i][j])
return 0;
}
}
return 1;
}
void main()
{
int a[4][4], assign, xpos = 0, ypos = 0, asc_result, rep_result;
srand((unsigned)time(NULL));
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
{
if (i == 0 && j == 0)
a[i][j] = 0;
else
{
do {
assign = rand() % 50;
rep_result = check_rep(a, assign);
} while (rep_result == 0);
a[i][j] = assign;
}
}
cout << "\n\nArrange the 4x4 matrix into ascending order. (Consider 0 as a blank space)" << endl;
for (int i = 0; i < 4; i++)
{
cout << endl;
for (int j = 0; j < 4; j++)
cout << a[i][j] << '\t';
}
do {
swap(a, xpos, ypos);
system("cls");
for (int i = 0; i < 4; i++)
{
cout << endl;
for (int j = 0; j < 4; j++)
cout << a[i][j] << '\t';
}
asc_result = check_asc(a);
} while (asc_result == 0);
cout << "\n\tYou win"<<endl;
system("pause");
}
Simple, just extend your swap function with a piece of code that will check whether the location of the element to be swapped is adjacent to the location of 0:
void swap(int a[][4], int &xpos, int &ypos)
{
...
if (a[i][j] == arr &&
((i == xpos && (j == ypos - 1 || j == ypos + 1)) ||
(j == ypos && (i == xpos - 1 || i == xpos + 1))))
{
temp = a[xpos][ypos];
a[xpos][ypos] = a[i][j];
a[i][j] = temp;
xpos = i;
ypos = j;
return;
}
An improvement would be to separate the check condition and inform the user in case when the element is not adjacent to 0.
Rough Algorithm
1) create a function find location, it will return a structure Point that has x, y integer fields, it will find the x, y location of any piece based on the pieces value, i.e. lets say 0 is entered, if it is located in the top left corner (0,0), a point (0, 0) will be returned
2) create a function that takes in 2 points, the location of the '0' and the location of the piece we wish to swap lets call it S, if S.x = 0.x and 0.y - 1 = S.y or S.y - 0.y + 1 then you know that said piece is directly above or below the 0, now of course you have ot add a few conditions for boundaries so as we dont check outside the grid. Have this function return an int 1 if the piece S is located above/below/beside, 0 if not.
3) if 1 is returned your allowed to do the flip, if 0 is returned find another piece