Iteration and output through a 2d array? - c++

I am trying to code a "Conways Game of Life" Visualization. I think I have a solid idea on how to go about it but my issue I am running into is this: When I attempt to output the rows and columns of my 2d array, it starts jumping between numbers towards the end and it never stops scrolling the numbers. It seems to get caught on the "x" of 78.
#include <iostream>
#include <cstring>
#include <cstdlib>
#define HEIGHT 25
#define WIDTH 80
using namespace std;
void makeBoard();
int seed = 0;
int main()
{
makeBoard();
}
void makeBoard()
{
int board[79][24] = {0};
/* Seed the random number generator with the specified seed */
srand(seed);
for(int x = 0; x <= 79; x++)
{
for(int y = 0; y <= 24; y++)
{
/* 50% chance for a cell to be alive */
if(rand() % 100 < 50)
{
board[x][y] = {1};
}
else
{
board[x][y] = {0};
}
/*if(board[x][y] == 1) {
cout << "SPAM" << endl;
}*/
//this is just printing out the current location it is iterating through.
cout << "X: " << x << " Y: " << y << endl;
}
cout << endl;
}
}
all of the code needed to run it should be right there.
Thank you for your help and patience.

Your indices are out of bounds. an array of [79][24] has indices going from 0-19, and 0-23. Your condition stop at 79 and 24 respectively. Replace <= with <.

An array of size N goes from 0 to n-1. You need to replace the <= with <, since you're running out of bounds along each dimension of the array.
Note also that you only have 79 columns and 24 rows, not the 80 and 25 you defined at the top of your program. You can fix this by doing:
int board[HEIGHT][WIDTH];
Then substitute the 79 and 24 with HEIGHT and WIDTH respectively, and change the <= in the loop conditions to <. That way all you need do is change those single values at the top to change the size of the board throughout.

Related

Printing on specific parts of the terminal

So for my university homework we are supposed to make a simple game of a 2D map with entities etc.
So I've figured a way of printing a map through it's dimensions and text formatting yet in our lessons it wasn't mentioned how we print on specific parts of the terminal. I've checked same questions but can't seem to get a solution.
Here is the code I use to print the map and make it's array. BLUE_B,STANDARD_B,OUTLINE and GREEN_B are declared above for the sake of color enrichment. Also IF POSSIBLE I don't want to use OS specific commands unless it's completely necessary. I use VS Code for Windows, compile with g++ on WSL Ubuntu-20.04.
for (int row = 0; row < i; row++) {
cout << OUTLINE "##";
for (int column = 0; column < j; column++) {
int n = rand() % 10; // According to "rand()"'s value we print either green, blue, or trees
if (n >= 3) { // We've assigned more values to green, in order to be more possible to be printed
cout << GREEN_B " "
STANDARD_B;
map[row][column] = 1;
} else if (n == 0 || n == 1) {
cout << BLUE_B " "
STANDARD_B;
map[row][column] = 0;
} else if (n == 2) {
int tree = rand() % 2;
cout << TREES "<>"
STANDARD_B;
map[row][column] = 0;
}
}
cout << OUTLINE "##"
STANDARD_B << endl;
}
for (i = 0; i < j + 2; i++) { // Bottom map border printing
cout << OUTLINE "##"
STANDARD_B;
}
If I understand the question correctly, you might be looking for iomanip. It is just one way of doing it. You can use setw and setfill to position different text in different areas. You can set different options for different outputs.
To move the text cursor to a specific line and column you need a “gotoxy”-style function.
Here is something that will work on both Linux terminals and the Windows Terminal. (It will not work on Windows Console without additional initialization help.)
#include <iostream>
const char * CSI = "\033[";
void gotoxy( int x, int y )
{
std::cout << CSI << (y+1) << ";" << (x+1) << "H";
}
Coordinates are (0,0) for the UL corner of the terminal. Here is a working example of use:
// continuing from above
#include <string>
int main()
{
// Clear a 40 x 10 box
for (int y = 0; y < 10; y++)
{
gotoxy( 0, y );
std::cout << std::string( 40, ' ' );
}
// Draw our centered text
gotoxy( 14, 5 );
std::cout << "Hello there!";
// Go to bottom of box and terminate
gotoxy( 0, 10 );
std::cout.flush();
}
For your game
I suggest you move the cursor to HOME (0,0) and draw the changed parts of your gameboard each frame.
I suppose that if you are on a local computer and your gameboard is relatively simple, you could probably get away with a complete redraw each frame...
Are you sure there is no professor-supplied macro or command to move the cursor home? (...as he has supplied magic macros to change the output color)?

How to display the input value?

When the is 200 the program doesn't read it. How to solve this problem? The program needs to print the ranges and the numbers but if the user input 200 it doesn't work. For example the user input numbers 180, 190, 200. The expected out put is 3 but the output is only 2. See the image attached for more details.
Note that in the statement:
results[scores[i] / 25]++;
You should check that the expression scores[i] / 25 is within the size of the vector results otherwise this is undefined behavior.
In your case, for the value 200 the expression scores[i] / 25 comes out to be 8. But since the size of the results vector is 7, your going out of bounds and this leads to undefined behavior.
You can use std::vector.at() member function to prevent this from happening. So you can modify that statement to look like:
results.at(scores[i] / 25)++;//this will throw if you go out of bounds
This has the advantage that your program will now not have undefined behavior.
You can also add a check to see if scores[i] / 25 is greater than or equal to the size of the results vector, then you can ask the user again for input.
If you'd like to use fixed-sized vectors, make sure the largest input score isn't too large. In my example, you can take the min of the input value and the largest allowed number. If you have N=25 buckets, and the largest number you accept is 200, then 200/25=8 is the largest bucket index you would like to reach, meaning you need a bucket of size 9.
#include <iostream>
#include <vector>
using namespace std;
double largest_allowed_score = 200; // if a score is larger than this, use this value isntead of the score
size_t N = 25; // number of entries to read in, results has the size of largest_allowed_score/N + 1
```cpp
#include <iostream>
#include <vector>
using namespace std;
double largest_allowed_score = 200; // if a score is larger than this, use this value isntead of the score
size_t N = 25; // number of entries to read in, results has the size of largest_allowed_score/N + 1
int main()
{
vector<double> scores(N);
cout << "Enter Score: \n";
for (size_t i = 0; i < N; ++i)
{
double val;
cin >> val;
val = min(val, largest_allowed_score);
scores[i] = val;
}
size_t res_size = static_cast<int>(largest_allowed_score) / N + 1; // the number of buckets, result size, or resolution
vector<double> results(res_size);
// count the occurances in each bucket
for (size_t i = 0; i < N; i++)
results[static_cast<int>(scores[i]) / N]++;
// print the buckets
for (size_t i = 0; i < res_size; i++)
cout << i * N << " - " << (i + 1) * N << ": " << results[i] << endl;
return 0;
}

How to output the same number of 0's for whichever x = to

For e.g. X=12 need to get the same number of 0's added to the end of the below var
The output should look something like allHeKnows = 1000000000000
For any X = single digit will display the correct output, however
Not sure how to reset, or what condition to add that in order for any X >= 10 to display the int allHeKnows value accordingly
#include <iostream>
using namespace std;
int main () {
int X, allHeKnows = 1, i=0;
cin >> X;
while ((X > 0 && X <100) && (i!=X)) {
i++;
allHeKnows = allHeKnows * 10;
cout << "this is allHeKnows: " << allHeKnows << "\n";
}
return 0;
}
One problem that I see initially is that once you get past 10 digits you surpass the max int value allowed by c++. You would be better off converting to a string if you are trying to reach those higher numbers.

Sorting output numbers without an array

So the main task is to find all numbers divisible by 7 between 0 - 100 then sort them in descending order without using an array. I'm just starting c++ and one of my first lab tasks was this, however when I finished it I was told that I shouldn't have used an array. I'm now curious as to how to do so otherwise. The code here only finds the numbers divisible by 7 and naturally displays them in an ascending sort.
I'm unsure how I would sort them without storing the value in an array then changing switching the values that way.
#include <iostream>
using namespace std;
int main() {
for( int i = 0; i <= 100; i++){
if(i%7 == 0){
//Display every integer divisible by 7
cout << i << endl;
}
}
return 0;
}
One approach is to find the lagest number divisible by 7 (here, 98) and just continue removing 7 to it until you run across the lowest boundary.
Just reverse the for loop:
for( int i = 100; i >= 7; i--){ //There is no integer lower than 7 that is divisible by 7
if(i%7 == 0){
cout << i << endl;
}
}
Change your loop to go in descending order; then you won't have to sort anything.
What you can do is start at max and go down from there; as follows:
for(int i = 100; i >= 0; i--){
if(i % 7 == 0){
cout << i << endl;
}
}
Bling it like its 2020 .. (You will get great grades ;-) )
#include <iostream>
using namespace std;
int main() {
int i=101;
while(--i)i%7?cout:cout<<i<<endl;
}

Plotting Coordinates from a .txt File

I am finishing the second half of a two-part assignment on Conway's Game of Life. I created a function to generate a random array of 1s and 0s; the 1s represent a living cell and the zero an empty space. I created a separate function to inspect the neighborhood and make a count to determine how the game progresses. The rules: if a cell has 2 or 3 neighbors it survives, more than 3 or less than 2 it dies, and if an empty space has 3 neighbors it is "born". I even got help from you guys to wrap the screen using the modulus, but I am having trouble importing a .txt file to finish part two. Here is the code for part one:
#include <iostream> //includes input-output stream
#include <time.h> //includes time function
#include <iomanip> //includes setprecision function
#include <unistd.h> //includes sleep function
#include <fstream> //includes ifstream function
using namespace std; //using standard library
int master[24][79]; //initializes primary data array
int h = 24; // initializes height variable
int w = 79; // initialises width variable
int noOfCycles; //initialize cycles variable
void gen0 (int master[24][79]); // creates initial generation
void life(int master[24][79]); //initializes life function
void copy(int arrayX[24][79], int arrayY[24][79]); //initializes cycle update function
void print(int master[24][79]); //initializes print function
void fillPercent (int master[24][79]); //initializes percentage calculating function
int main() //initialize main function
{
cout << "How many cycles would you like to run?"; //prompt user to input cycles
cin >> noOfCycles; //user inputs cycles
srand (time(0)); //creates initial randomness
gen0(master); //creates initial generation
for (int k = 0; k <= noOfCycles; k++) //prints gen0 and cycles 50 times
{
print(master); //prints current array
fillPercent(master); //calculates/prints fill percentage
cout << " Cycle #" << k << " Author: Mikhail Morgan" << endl << endl;
//prints cycle number and signature
life(master); //calls life function
sleep(1); //delays output by 1 second
} //end width loop
} //end main function
void gen0 (int master[24][79])
{
for(int j = 0; j < h; j++) //height loop
{
for (int i = 0; i < w; i++) //width loop
master[j][i] = rand() % 2; //creates random generation 0
} //end height loop
}
void print(int master[24][79]) //Prints array
{
for(int j = 0; j < h; j++) //height loop
{
for(int i = 0; i < w; i++) //width loop
{
if(master[j][i] == 1)
cout << '0'; //print living cells as zeros
else
cout << ' '; //print dead cells as spaces
} // end width loop
cout << endl;
} // end height loop
} //end print function
void fillPercent (int master[24][79]) // calculates fill percentage
{
double fillNumber = 0; //resets every cycle
for (int i = 0; i < h; i++ ) //width loop
{
for (int j = 0; j < w; j++ ) //height loop
{
fillNumber += master[i][j]; //increments fill number
} //end height loop
} //end width loop
cout << endl << fixed << setprecision(2) << (fillNumber/(w*h))*100; //print percentage
} //end fillPercent function
void life (int master[24][79]) //generates/kills cells based on neighborhood
{
int temp[24][79]; //temporary array for manipulating data
copy (master, temp); //copy array onto temp
for(int j = 0; j < h; j++) //height loop
{
for (int i = 0; i < w; i++) //width loop
{
int count = 0; //intialize neighbor count variable
count = master[(j-1+h) % h][i % w] + //searches down
master[(j-1+h) % h][(i-1+w) % w] + //down left
master[j % h][(i-1+w) % w] + //left
master[(j+1+h) % h][(i-1+w) % w] + //up left
master[(j+1+h) % h][i % w] + //up
master[(j+1+h) % h][(i+1+w) % w] + //up right
master[j % h][(i+1+w) % w] + //right
master[(j-1+h) % h][(i+1+w) % w]; //down right
//cell dies if count falls below 2 or rises above 3
if(count < 2 || count > 3)
temp[j][i] = 0;
//cell stays alive if it has two neighbors
if(count == 2)
temp[j][i] = master[j][i];
//cell either stays alive or gets born if three neighbors
if(count == 3)
temp[j][i] = 1;
} //end width loop
}//end height loop
copy(temp, master); //copy temp back to main array
} //end life function
void copy(int arrayX[24][79], int arrayY[24][79]) //Copy machine
{
for(int j = 0; j < h; j++) //height loop
{
for(int i = 0; i < w; i++) //width loop
arrayY[j][i] = arrayX[j][i]; //temporary arrays used for copying
} //end height loop
} //end copy function
I know, using namespace std is lame af but it's mandated by my dinosaur-of-a-professor.
My problem is that for part two he wants us to stream the coordinates for the initial generation from a file that he supplied called GliderGun.txt. I am using Xcode and Im 99% sure that I have the file in the right location: I can see it in the right hand menu inside the same folder as main.cpp, and I can see the original copy in the Finder menu next to main.cpp. The first line is not a coordinate pair, it is the total number of coordinates in the file... Im not sure what the purpose of that is, and I suspect its whats messing me up. Here is the text from the file itself:
36
1 25
2 23
2 25
3 13
3 14
3 21
3 22
3 35
3 36
4 12
4 16
4 21
4 22
4 35
4 36
5 1
5 2
5 11
5 17
5 21
5 22
6 1
6 2
6 11
6 15
6 17
6 18
6 23
6 25
7 11
7 17
7 25
8 12
8 16
9 13
9 14
Here is the code for the function that replaces gen0. All I did was replace the call for gen0 with getPattern and altered the definition to look like this:
void getPattern (int master[24][79]) //generates Glider Gun
{
ifstream infile("GliderGun.txt", ios::in);
infile.open("GliderGun.txt", ios::in);//opens .txt file
int numOfCoordinates; // number of coordinate pairs
int i, j; // x, y coordinates
infile >> numOfCoordinates;
for (int a = 0; a < numOfCoordinates; a++)
{
infile >> i >> j;
master[j][i] = 1;
}
infile.close(); // closes .txt file
}
The console produces a blank 24x79 array. I sense that I have a looping problem but I dont know enough about how ifstream works to fix it. The coordinates are listed as (x y) or as defined by my other loops, (j i). I don't need the console to print the file I just need it to write 1s in the coordinates that are listed. Thanks for any advice!
Just from trying to reason about your code, there are two problems that arise from a drop-in replacement of getPattern where gen0 used to be:
You don't initialize any of the slots of your array to zero.
You're reading in the number of lines as an x-coordinate for one of the cells, all of the x-coordinates as y-coordinates, most of the y-coordinates as x-coordinates, and not reading the last y-coordinate.
There are two simple enough changes you can make to fix this.
Before reading from the file set the value in all cells of your 2D-array to 0.
Even if you're not doing anything with it, read in the number of lines from the file before looping over the coordinates.
Unrelated to your code, the text file does not need to be in the same directory as the source file, it needs to be in the same directory that the program is executed from. I don't know where the execution will be done from in XCode, but it might be worth testing directly from your computer's shell, if you know how.
Edit:
The part of getPattern where you read from the file could look something like this:
int num_coordinates; // This will be the number of coordinate pairs your file says it has.
int i, j; // These will be your x, y coordinates.
infile >> num_coordinates;
for (int loop_ct = 0; loop_ct < num_coordinates; loop_ct++) {
infile >> i >> j;
master[j][i] = 1;
}