Draw a ASCII-art Christmas tree in C++ - c++

I want to draw a ASCII-art Christmas tree in C++ using functions with parameters.
This is what I have got so far, which works for the most part however when drawing the actual body of the tree (leaves) it seems to repeat it multiple times.
This effect seems to increase as the height of the tree does as well. So for example if a height of 4 is entered for the tree then the body will be drawn 2 times. if the height is 5, then it is drawn 3 times. 6 is 4 times and so on.
Any help?
#include <iostream>
using namespace std;
const char BLANK = ' ';
const char LEAF = '#';
const char WOOD = '|';
void drawAXmasTree();
void drawFoliage(int);
void drawTrunk(int);
void getValidHeight(int&);
void drawALineOfFoliage(int, int);
int main()
{
cout << "Due on 11 December 2018 \n\n";
drawAXmasTree();
}
void drawAXmasTree()
{
int treeHeight = 0;
getValidHeight(treeHeight); //read in a valid value for the tree height
drawFoliage(treeHeight); //draw tree foliage
drawTrunk(treeHeight); //draw tree trunk
}
void drawFoliage(int trHgt) //draw the foliage
{
int branchLine = 1;
int treeHeight = trHgt;
while (branchLine <= (trHgt - 2))
{
drawALineOfFoliage(treeHeight, branchLine);
branchLine += 1;
}
}
void drawTrunk(int trHgt) //draw the trunk
{
int trunkLine = 1;
int spaces;
while (trunkLine <= 2) // for each line in the truck
{
spaces = 1;
while (spaces <= (trHgt - 2)) //draw the spaces on the left
{
cout << BLANK;
spaces += 1;
}
cout << WOOD; //draw the truck
cout << endl; //go to next line
trunkLine += 1;
}
}
void getValidHeight(int& trHgt)
{
do
{
cout << "Enter the size of the tree(4 - 20): ";
cin >> trHgt;
if (trHgt < 4 || trHgt > 20)
{
cout << "ERROR: Invalid height! ";
}
}
while (trHgt < 4 || trHgt > 20);
}
void drawALineOfFoliage(int trHgt, int brLine)
{
int treeHeight = trHgt;
int branchLine = brLine;
int spaces = trHgt - 2;
for (int i = 0; i < (treeHeight - 2); i++) {
for (int j = spaces; j > 0; j--)
{
cout << BLANK;
}
for (int foliage = 0; foliage <= i * 2; foliage++)
{
cout << LEAF;
}
spaces--;
cout << endl;
}
}

The problem in your code is the following:
In the function drawFoliage you intended to loop and call drawALineOfFoliage for each line. But you actually draw the whole tree every time you call drawALineOfFoliage.
In order to fix you code, just replace drawFoliage for drawALineOfFoliage in the drawAXMasTree function, like this:
void drawAXmasTree()
{
int treeHeight = 0;
getValidHeight(treeHeight); //read in a valid value for the tree height
drawALineOfFoliage(treeHeight);
drawTrunk(treeHeight);
}
Notice you don't need the second argument in drawALineOfFoliage since you don't actually use it.
As for drawFoliage, you can just erase it.

Thanks for the help, I managed to resolve this because like people said it was drawing the whole tree rather than just one line. All I had to do was change the drawALineOfFoliage function to the following;
void drawALineOfFoliage(int trHgt, int brLine)
{
int treeHeight = trHgt;
int branchLine = brLine - 1;
int spaces = trHgt - 2;
for (int i = spaces; i > branchLine; i--)
{
cout << BLANK;
}
for (int foliage = 0; foliage <= branchLine * 2; foliage++)
{
cout << LEAF;
}
spaces--;
cout << endl;
}

Check this out:
#include <iostream>
using namespace std;
const char BLANK = ' ';
const char LEAF = '#';
const char WOOD = '|';
void drawAXmasTree();
void drawFoliage(int);
void drawTrunk(int);
void getValidHeight(int&);
void drawALineOfFoliage(int, int);
int main()
{
cout << "Due on 11 December 2018 \n\n";
drawAXmasTree();
system("pause");
}
void drawAXmasTree()
{
int treeHeight = 0;
getValidHeight(treeHeight);
drawFoliage(treeHeight);
drawTrunk(treeHeight);
}
void drawFoliage(int trHgt)
{
int branchLine = 1;
int treeHeight = trHgt;
while (branchLine <= (trHgt - 2))
{
drawALineOfFoliage(treeHeight, branchLine);
branchLine += 1;
}
}
void drawTrunk(int trHgt)
{
int trunkLine = 1;
int spaces;
for (trunkLine; trunkLine <= 2; trunkLine++)
{
for (spaces = 1; spaces <= (trHgt - 1); spaces++)
{
cout << BLANK;
}
cout << WOOD;
cout << "\n";
}
}
void getValidHeight(int& trHgt)
{
do
{
cout << "Enter the size of the tree(4 - 20): ";
cin >> trHgt;
if (trHgt < 4 || trHgt > 20)
{
cout << "ERROR: Invalid height! ";
}
} while (trHgt < 4 || trHgt > 20);
}
void drawALineOfFoliage(int trHgt, int brLine)
{
int treeHeight = trHgt;
int branchLine = brLine;
int spaces(0);
int tree(0);
for (spaces; spaces < (trHgt - branchLine); spaces++)
{
cout << BLANK;
}
for (tree; tree < (branchLine * 2 - 1); tree++)
{
cout << LEAF;
}
cout << endl;
}

Related

For loop repetition drawing trouble

I'm trying to get a loop to draw a Christmas tree but the output is wrong, I've tried searching for the answer but i can't seem to find it and I'm stumped. The answer may be obvious but I've missed a lot and any help's greatly appreciated!
#include <iostream>
#include <assert.h>
#include <iomanip>
using namespace std;
const char blank = ' ';
const char leaf = '#';
const char wood = '|';
const int minSize = 4;
const int maxSize = 20;
int treeHeight;
int& getValidHeight(int&);
void drawALineOfFoliage(int);
void drawFoliage(int);
void drawTrunk(int);
void drawAXmasTree(int);
void drawAXmasTree(int treeHeight) {
getValidHeight(treeHeight);
drawFoliage(treeHeight);
drawTrunk(treeHeight);
}
int& getValidHeight(int& treeHeight) {
cout << ("Please enter the size of the tree (4-20):\n");
cin >> treeHeight;
while ((treeHeight < minSize) || (maxSize < treeHeight)) {
cout << "ERROR: Invalid height! Enter the size of the tree (4-20):\n";
cin >> treeHeight;
return treeHeight;
}
}
void drawALineOfFoliage(int treeHeight) {
for (int x = 0; x < treeHeight; ++x){
for (int y = treeHeight; y > x; --y){
cout << blank;}
for (int y = 0; y < x; ++y){
cout << leaf;}}}
void drawFoliage(int treeHeight) {
int branchLine = 1;
do {
drawALineOfFoliage(treeHeight);
branchLine += 1;
} while (branchLine <= (treeHeight - 2));}
void drawTrunk(int treeHeight) {
int trunkLine(1), spaces;
while (trunkLine <= 2) {
spaces = 1;
while (spaces <= (treeHeight - 3)) {
cout << blank;
spaces += 1;}
cout << wood << "\n";
trunkLine += 1;
}
}
int main()
{
drawAXmasTree(treeHeight);
system("pause");}
the output is just the Christmas tree deconstructed so all
the levels are on the same line and repeated several times
So I took your sample code and gave it a run.
First of all, your styling and tabbing is inconsistent which can make the code really hard to read.
Next, your drawALineOfFoliage is actually drawing the entire tree without the trunk instead of just a line. Therefore you were missing a cout << endl; inside the main for loop after the other 2 nested for loop.
Begin edit:
EDIT: I forgot to talk about the half tree.
So in your existing code, it only prints half the tree. Something like this...
#
##
###
####
Which is half a Christmas tree. To make it look similar to an actual tree, all I did was adding *2 to the for loop that is responsible for printing the leaf. (You can also do cout << leaf << leaf; instead)
for (int y = 0; y < x*2; ++y) {
cout << leaf;
}
End edit.
Since your drawALineOfFoliageis printing the tree already, in drawFoliage,
do {
drawALineOfFoliage(treeHeight);
branchLine += 1;
} while (branchLine <= (treeHeight - 2));
this do while loop is looping the amount of trees (again, without trunk) so it should be removed.
Now that we got the top part done, let's take a look at the trunk.
while (spaces <= (treeHeight - 3))
The - 3 seems to came out of nowhere. And it is only printing one | per row which looks kinda weird so I removed the - 3 and make it print 2 woods instead.
Now the output looks somewhat like this...
Please enter the size of the tree (4-20):
6
##
####
######
########
##########
||
||
Its alright but still weird. TLDR, I did some tweaking and got an end result like this...
Please enter the size of the tree (4-20):
7
#
###
#####
#######
#########
###########
#############
|||
|||
Full code as follows:
#include <iostream>
#include <assert.h>
#include <iomanip>
using namespace std;
const char blank = ' ';
const char leaf = '#';
const char wood = '|';
const int minSize = 4;
const int maxSize = 20;
int treeHeight;
int& getValidHeight(int&);
void drawALineOfFoliage(int);
void drawFoliage(int);
void drawTrunk(int);
void drawAXmasTree(int);
void drawAXmasTree(int treeHeight) {
getValidHeight(treeHeight);
drawFoliage(treeHeight);
drawTrunk(treeHeight);
}
int& getValidHeight(int& treeHeight) {
cout << ("Please enter the size of the tree (4-20):\n");
cin >> treeHeight;
while ((treeHeight < minSize) || (maxSize < treeHeight)) {
cout << "ERROR: Invalid height! Enter the size of the tree (4-20):\n";
cin >> treeHeight;
}
return treeHeight;
}
void drawALineOfFoliage(int treeHeight) {
for (int x = 0; x < treeHeight; ++x) {
for (int y = treeHeight; y > x; --y) {
cout << blank;
}
for (int y = 0; y < x*2; ++y) {
cout << leaf;
}
cout << endl;
}
}
void drawALineOfFoliageOdd(int treeHeight) {
for (int x = 0; x < treeHeight; ++x) {
for (int y = treeHeight; y > x; --y) {
cout << blank;
}
cout << leaf;
for (int y = 0; y < x*2; ++y) {
cout << leaf;
}
cout << endl;
}
}
void drawFoliage(int treeHeight) {
int branchLine = 1;
drawALineOfFoliageOdd(treeHeight);
do {
branchLine += 1;
} while (branchLine <= (treeHeight - 2));
}
void drawTrunk(int treeHeight) {
int trunkLine(1), spaces;
while (trunkLine <= 2) {
spaces = 1;
while (spaces <= (treeHeight - 1)) {
cout << blank;
spaces += 1;
}
cout << wood << wood << wood << endl;
trunkLine += 1;
}
}
int main() {
drawAXmasTree(treeHeight);
system("pause");
}
Note: I did not do any sort of cleanup so there are a lot of unnecessary codes in it. I just worked on top of what you have to provide you the best solution I got.
Your lineOfFoliage seems to do lines for all x < height. It seems to me that the basic structure of the foliage drawing code would be:
drawFoliage(height) {
for(width = 0..height) cout << centeredLine(width);
}
drawCenteredLine(width) {
return blanks + leafs;
}

What character is this?

I'm writing a simple program to generate a box with a user-defined sidelength and border/fill characters. Everything is working as I want it to, except when it prints the box to the terminal, it produces a strange character I cannot find anywhere. I feel like if I know what it is, I might be able to fix it. My header file is here:
#ifndef Box_h
#define Box_h
class Box
{
private:
int pSidelength;
char pBorder;
char pFill;
public:
Box(int pSidelength, char pBorder = '#', char pFill = '*');
int Sidelength;
char Border;
char Fill;
int Area();
int Perimeter();
int GetSize();
int Grow();
int Shrink();
char SetBorder();
char SetFill();
void Draw();
void Summary();
};
#endif Box_h
My source for the class is:
#include <iostream>
#include "box.h"
#include <iomanip>
using namespace std;
Box::Box(int pSidelength, char pBorder, char pFill)
{
if (pSidelength < 1)
{
Sidelength = 1;
}
else if (pSidelength > 39)
{
Sidelength = 39;
}
else
{
Sidelength = pSidelength;
}
if (pBorder != '#')
{
SetBorder();
}
if (pFill != '*')
{
SetFill();
}
}
int main(void)
{
Box MyBox1(3,'#','*');
Box MyBox2(7, '^', '*');
Box MyBox3(10, '$', '%');
MyBox1.Grow();
MyBox2.Shrink();
MyBox1.Summary();
MyBox2.Summary();
MyBox3.Summary();
return 0;
}
int Box::Shrink()
{
if (Sidelength == 1)
{
Sidelength = Sidelength;
}
else
{
Sidelength = Sidelength - 1;
}
return Sidelength;
}
int Box::Grow()
{
if (Sidelength == 39)
{
Sidelength = Sidelength;
}
else
{
Sidelength = Sidelength + 1;
}
return Sidelength;
}
char Box::SetFill()
{
Fill = pFill;
return Fill;
}
char Box::SetBorder()
{
Border = pBorder;
return Border;
}
int Box::Area()
{
int area = (Sidelength)*(Sidelength);
return area;
}
int Box::Perimeter()
{
int perimeter = 4 * (Sidelength);
return perimeter;
}
int Box::GetSize()
{
int size = Sidelength;
return size;
}
void Box::Draw()
{
int j = 1;
int k = 1;
if (Sidelength == 1 || Sidelength == 2)
{
for (int i = 1; i <= Sidelength; i++)
{
while (j <= Sidelength)
{
cout << setw(2) << Border;
j++;
}
j = 1;
}
cout << endl;
}
else
{
for (int i = 1; i <= Sidelength; i++)
{
if (i == 1 || i == Sidelength)
{
while (k <= Sidelength)
{
cout << setw(2) << Border;
k++;
}
cout << endl;
k = 1;
}
else
{
while (j <= Sidelength)
{
if (j == 1 || j == Sidelength)
{
cout << setw(2) << Border;
}
else
{
cout << setw(2) << Fill;
}
j++;
}
cout << endl;
j = 1;
}
}
cout << endl;
}
}
void Box::Summary()
{
cout << "The Sidelength of the box is: " << Box::GetSize() << endl;
cout << "The Perimeter of the box is: " << Box::Perimeter() << endl;
cout << "The Area of the box is: " << Box::Area() << endl;
Box::Draw();
}
The program has a default character associated with Border/Fill, as specified in the header file. When run, it produces this:
What character is that, and any ideas on why it would be appearing in the first place?
The character is random, and could in theory be different every time you run the program.
It's coming from the pBorder member, which is never set to anything.
You got confused with same name of variables.
Box::Box(int pSidelength, char pBorder, char pFill)
{
if (pSidelength < 1)
{
Sidelength = 1;
}
else if (pSidelength > 39)
{
Sidelength = 39;
}
else
{
Sidelength = pSidelength;
}
if (pBorder != ' ') //Here pBorder has '*' but this is local
// pBorder to this Function
{
SetBorder();
}
if (pFill != ' ')
{
SetFill();
}
}
And When you call SetBorder();
It makes Border as pBorder as that was declared in the class which is still unintialized.
char Box::SetBorder()
{
Border = pBorder; //This pBorder is not initialized
return Border;
}
Solution 1
Dont use Function
if (pBorder != ' ')
{
Border = pBorder;
}
Solution 2
Pass pBorder
if (pBorder != ' ')
{
SetBorder(pBorder);
}
char Box::SetBorder(char pBorder)
{
Border = pBorder; //This pBorder is not initialized
return Border;
}

why increment variable changing the value of the array when they have different names

Can someone please help me. I am struggling to find in my code why the last value in column B always gets incremented by one. I have written some code since its an assignment due today. I also cant figure out why the last value in column B is not equal to 196 because in the reset function it sets all the values in the array to 196 . Any suggestion would be appreciated. Thank you in advance
#include <iostream> //includes cin cout
#include <iomanip>
using namespace std; //setting up the environment
const int NUMBER_OF_ROWS = 3;
const int NUMBER_OF_COLUMNS = 3;
void printAllSeats(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]);
void reset(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]);
void askForUsersSeat(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS], int &SeatCountNumber, bool &anyFreeSeats);
bool isFull(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]);
bool isEmpty(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]);
int main() { //main starts
int maxSeats;
int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
int SeatCountNumber = 0;
bool anyFreeSeats;
reset(seats);
anyFreeSeats = true;
SeatCountNumber = 0;
while (anyFreeSeats) {
printAllSeats(seats);
askForUsersSeat(seats, SeatCountNumber, anyFreeSeats);
}
system("pause");
return 0;
} //main ends
void printAllSeats(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]) {
cout << endl;
cout << setw(10) << " - = Available R = Reserved\n\n";
for (int i = 0; i <= NUMBER_OF_ROWS; i++) {
cout << setw(15) << i << " ";
for (int j = 0; j < NUMBER_OF_COLUMNS; j++) {
if (i == 0) {
cout << " " << static_cast<char>(j + 65) << " ";
} else {
cout << " " << static_cast<char>(seats[i][j]) << " ";
}
}
cout << endl;
}
cout << endl;
}
void reset(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]) {
//set all values in array to 196
for (int i = 0; i <= NUMBER_OF_ROWS; i++) {
for (int j = 0; j <= NUMBER_OF_COLUMNS; j++) {
seats[i][j] = 196;
}
}
}
void askForUsersSeat(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS], int &SeatCountNumber, bool &anyFreeSeats) {
int seatChoiceNumber;
char seatChoiceLetter;
int letter;
int maxSeats = NUMBER_OF_ROWS * NUMBER_OF_COLUMNS;
cout << "Seat (Row, Column): ";
cin >> seatChoiceNumber >> seatChoiceLetter;
letter = static_cast<int>(toupper(seatChoiceLetter));
if (((letter >= 65) && (letter < (65 + NUMBER_OF_COLUMNS))) && ((seatChoiceNumber > 0) && (seatChoiceNumber <= NUMBER_OF_ROWS))) {
if (seats[(seatChoiceNumber)][(letter - 65)] == 82) {
} else {
seats[(seatChoiceNumber)][(letter - 65)] = 82;
SeatCountNumber++; //this changes last value in column B for some reason
if (SeatCountNumber < maxSeats) {
anyFreeSeats = true;
}
else if (SeatCountNumber > maxSeats) {
printAllSeats(seats);
anyFreeSeats = false;
}
}
} else {
}
}
I kind of cleaned up the code a bit. It seems you found your answer in the comments, so I just did some indentation. Try and eliminate whitespaces in your code (mind you, the one I am putting here is not perfect either, but you get the point). Clean and easy to read code doesn't only make it better for you, but as you get higher up in the industry and other people begin reading and working on your code, having clean and easy to read code really helps :)
#include <iostream> //includes cin cout
#include <iomanip>
using namespace std; //setting up the environment
const int NUMBER_OF_ROWS = 3;
const int NUMBER_OF_COLUMNS = 3;
void printAllSeats(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]);
void reset(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]);
void askForUsersSeat(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS], int &SeatCountNumber, bool &anyFreeSeats);
bool isFull(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]);
bool isEmpty(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]);
int main()
{
int maxSeats;
int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
int SeatCountNumber = 0;
bool anyFreeSeats;
reset(seats);
anyFreeSeats = true;
SeatCountNumber = 0;
while (anyFreeSeats)
{
printAllSeats(seats);
askForUsersSeat(seats, SeatCountNumber, anyFreeSeats);
}
system("pause");
return 0;
} //main ends
void printAllSeats(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS])
{
cout << endl;
cout << setw(10) << " - = Available R = Reserved\n\n";
for (int i = 0; i <= NUMBER_OF_ROWS; i++)
{
cout << setw(15) << i << " ";
for (int j = 0; j < NUMBER_OF_COLUMNS; j++)
{
if (i == 0)
{
cout << " " << static_cast<char>(j + 65) << " ";
}
else
{
cout << " " << static_cast<char>(seats[i][j]) << " ";
}
}
cout << endl;
}
cout << endl;
}
void reset(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS])
{
//set all values in array to 196
for (int i = 0; i <= NUMBER_OF_ROWS; i++)
{
for (int j = 0; j <= NUMBER_OF_COLUMNS; j++)
{
seats[i][j] = 196;
}
}
}
void askForUsersSeat(int seats[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS], int &SeatCountNumber, bool &anyFreeSeats)
{
int seatChoiceNumber;
char seatChoiceLetter;
int letter;
int maxSeats = NUMBER_OF_ROWS * NUMBER_OF_COLUMNS;
cout << "Seat (Row, Column): ";
cin >> seatChoiceNumber >> seatChoiceLetter;
letter = static_cast<int>(toupper(seatChoiceLetter));
if (((letter >= 65) && (letter < (65 + NUMBER_OF_COLUMNS))) && ((seatChoiceNumber > 0) && (seatChoiceNumber <= NUMBER_OF_ROWS)))
{
if (seats[(seatChoiceNumber)][(letter - 65)] == 82)
{
}
else
{
seats[(seatChoiceNumber)][(letter - 65)] = 82;
SeatCountNumber++; //this changes last value in column B for some reason
if (SeatCountNumber < maxSeats)
{
anyFreeSeats = true;
}
else if (SeatCountNumber > maxSeats)
{
printAllSeats(seats);
anyFreeSeats = false;
}
}
}
else {
}
}
Note: Some more whitespaces could even come out but I generally like to have spaces after certain statements (personal preference).

Bubble Sort not working correctly

I've been working on this for awhile and I have tried multiple different algorithms for the bubble sort that I have found online but none of them are working properly for me and I'm pretty close to giving up, but this is due tomorrow night. I'd really appreciate if someone could point out where im going wrong. I dont really understand this algorithm with the bool so ill try to find what i was trying before and edit it in
#include <iostream>
using namespace std;
void GetInfo(int[], int&);
void BubbleSort(int[], int);
void BinarySearch(int[], int);
int main()
{
int size;
int array[500];
GetInfo(array, size);
BubbleSort(array, size);
BinarySearch(array, size);
return 0;
}
void GetInfo(int array[], int& size)
{
cout << "Enter the number of naturals: ";
cin >> size;
cout << "Enter the natural numbers to sort: ";
for (int i = 0; i < size; i++)
{
cin >> array[i];
}
}
void BubbleSort(int array[], int size)
{
int temp;
bool check = true;
int end = 0;
while(check)
{
end++;
check = false;
for(int i = 0; i < size - end; i++)
{
if (array[i] > array[i+1]) //I'm positive this part is correct
{
temp = array[i];
array[i] = array[i+1];
array[i+1] = temp;
check = true;
}
}
}
cout << endl << "Numbers sorted in ascending order: " << endl;
for (int i = 0; i < size; i++)
{
cout << array[i] << ' ';
}
}
void BinarySearch(int array[], int size) //this doesnt work properly atm but
{ //should be good when the sort works
int index;
int top = size - 1;
int bottom = 0;
int middle = (top) / 2;
bool found = false;
int target;
cout << endl << "Enter the number to search: ";
cin >> target;
while (found == false)
{
if (target > array[middle])
{
bottom = middle + 1 ;
middle = ((top - bottom)/2) + bottom;
}
else if (target < array[middle])
{
top = middle - 1;
middle = ((top - bottom)/2) + bottom;
}
else
{
found = true;
index = middle;
}
}
cout << "Number " << target << " is found in position " << index << endl;
}
You might meant to swap a[i] with a[i+1] while you actually swapped a[size+1]
These lines are wrong:
array[i] = array[size+1];
array[size+1] = temp;
You need:
array[i] = array[i+1];
array[i+1] = temp;

2D Array Help C++

OK so heres the scoop: I am building a minesweeper style program for my c++ class, I'm using a 2D array to create the board,and a second 2d array to store guesses. For each value in the board array, I run a random number gen and assign it a value between 0 and 99. Each value in the array is considered a bomb if its value is greater than 85. The program accepts user input and determines if it is a bomb. If it is not the corresponding bool array (isGuessed) position is changed to true. This bool array is then sent to the reDraw function to be redrawn. All false bools are displayed as '?' and all true are displayed as 'X'. However, when I reDraw, it changes multiple locations in the array to an X with only one guess. My thought is that the board is not drawn in connection with the array positions. Could someone help. Just to be clear, I'm trying to understand why the function reDraw is not working properly. Here is ALL my code.
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
//Function Prototypes
void reDraw (bool guessed [] [10], int rows, int columns);
void newBoard (int rows, int columns);
int main(int argc, const char * argv[])
{
//Declare Variables
const int ROWS = 10;
const int COLUMNS = 10;
int board [ROWS][COLUMNS];
bool wasGuessed [10] [10];
bool playAgain = true;
char newGame;
int rowGuess, columnGuess, numOfBombs = 0, score = 0;
bool bomb = false;
srand((unsigned) time(0));
// Welcome User, Give Direction
cout<<"\n\n\t\tWelcome To Matt's Minesweeper\n\n";
while (playAgain) {
//function to randomly populate array elements
for (int row = 0; row < ROWS; row++) {
for (int column = 0; column < COLUMNS; column++) {
board [row] [column] = rand() % 100;
if (board [row] [column] >= 85) { //counter for bombs
numOfBombs++;
}
}
}
// Create a new Display Board
newBoard(10, 10);
//Begin Game
cout<<"\nTotal Bombs In This Game: "<<numOfBombs;
// Process Guesses
do {
cout<<"\nPlease Input your ROW & COLUMN Guess coordinate (i.e. 3 2): ";
cin>>rowGuess>>columnGuess;
if (board [rowGuess] [columnGuess] >= 85) {
bomb = true;
cout<<"\n\n\t\tXXXXXX BOMB HIT XXXXXXX\n\t\t\tGame Over.\n\n";
cout<<"Your Score Score: "<<score;
cout<<"\n\n Play Again (y/n):";
cin>>newGame;
switch (newGame) {
case 'y':
cout<<"\n\n";
playAgain = true;
break;
default:
playAgain = false;
break;
}
} else {
wasGuessed [rowGuess] [columnGuess] = true;
score++;
reDraw(wasGuessed, 10, 10);
}
} while (!bomb);
}
return 0;
}
void reDraw (bool guessed [] [10], int rows, int columns)
{
// Format row and column headers
cout<<" 0 1 2 3 4 5 6 7 8 9\n";
cout<<"0";
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
if ((j+1) % 10 == 0)
if ((i+1) == 10) {
if (guessed [i] [j])
cout<<"X "<<" \n";
else
cout<<"? "<<" \n";
}else{
if (guessed [i] [j])
cout<<"X "<<" \n"<<i+1;
else
cout<<"? "<<" \n"<<i+1;
}
if ((j+1) % 10 != 0)
if (guessed [j] [i])
cout<<" X"<<" ";
else
cout<<" ?"<<" ";
}
}
}
void newBoard (int rows, int columns)
{
cout<<" 0 1 2 3 4 5 6 7 8 9\n";
cout<<"0";
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
if ((j+1) % 10 == 0)
if ((i+1) == 10) {
cout<<"? "<<" \n";
}else
cout<<"? "<<" \n"<<i+1;
if ((j+1) % 10 != 0)
cout<<" ?"<<" ";
}
}
}
Thanks For Your Help Guys!
Ok it's fixed. Check out the new code:
Changes - Added reset() and moved wasGuessed [rowGuess] [columnGuess] = true; to the top after cin<<.
It works like a charm and draws X's where the ?'s once stood before the guess.
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
//Declare Variables
const int ROWS = 10;
const int COLUMNS = 10;
int board [ROWS][COLUMNS];
bool wasGuessed [ROWS] [COLUMNS];
bool playAgain = true;
char newGame;
int rowGuess, columnGuess, numOfBombs = 0, score = 0;
bool bomb = false;
//Function Prototypes
void reDraw (bool guessed [] [10], int rows, int columns);
void newBoard (int rows, int columns);
void reset();
int main(int argc, const char * argv[])
{
srand((unsigned) time(0));
reset();
// Welcome User, Give Direction
cout<<"\n\n\t\tWelcome To Matt's Minesweeper\n\n";
while (playAgain) {
//function to randomly populate array elements
for (int row = 0; row < ROWS; row++) {
for (int column = 0; column < COLUMNS; column++) {
board [row] [column] = (rand() % 100) + 0;
if (board [row] [column] >= 85) { //counter for bombs
numOfBombs++;
}
}
}
// Create a new Display Board
newBoard(10, 10);
//Begin Game
cout<<"\nTotal Bombs In This Game: "<<numOfBombs;
// Process Guesses
do {
cout<<"\nPlease Input your ROW & COLUMN Guess coordinate (i.e. 3 2): ";
cin>>rowGuess>>columnGuess;
wasGuessed [rowGuess] [columnGuess] = true;
if (board [rowGuess] [columnGuess] >= 85) {
bomb = true;
cout<<"\n\n\t\tXXXXXX BOMB HIT XXXXXXX\n\t\t\tGame Over.\n\n";
cout<<"Your Score Score: "<<score;
cout<<"\n\n Play Again (y/n):";
cin>>newGame;
switch (newGame) {
case 'y':
cout<<"\n\n";
playAgain = true;
reset();
break;
default:
playAgain = false;
break;
}
} else {
wasGuessed [rowGuess] [columnGuess] = true;
score++;
reDraw(wasGuessed, 10, 10);
}
} while (!bomb);
}
return 0;
}
void reDraw (bool guessed [] [10], int rows, int columns)
{
// Format row and column headers
cout<<" 0 1 2 3 4 5 6 7 8 9\n";
cout<<"0";
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
if ((j+1) % 10 == 0)
if ((i+1) == 10) {
if (guessed [i] [j])
cout<<"X "<<" \n";
else
cout<<"? "<<" \n";
}else{
if (guessed [i] [j])
cout<<"X "<<" \n"<<i+1;
else
cout<<"? "<<" \n"<<i+1;
}
if ((j+1) % 10 != 0)
if (guessed [j] [i])
cout<<" X"<<" ";
else
cout<<" ?"<<" ";
}
}
}
void newBoard (int rows, int columns)
{
cout<<" 0 1 2 3 4 5 6 7 8 9\n";
cout<<"0";
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
if ((j+1) % 10 == 0)
if ((i+1) == 10) {
cout<<"? "<<" \n";
}else
cout<<"? "<<" \n"<<i+1;
if ((j+1) % 10 != 0)
cout<<" ?"<<" ";
}
}
}
void reset()
{
for (int row = 0; row < ROWS; row++)
{
for (int column = 0; column < COLUMNS; column++)
{
wasGuessed [row] [column] = false;
}
}
}
I was bored so I made your program better. It's all in one file, but it would be easy enough to split it into multiple. Just separate out the members and class definitions for each class, and put them in their own files, and put main in its own file.
I do a few things that might strike you as peculiar. If you see something, ask about it in a comment and I'll explain myself
// include all of the things
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <string>
// use all of the things
using std::rand;
using std::srand;
using std::time;
using std::cout;
using std::cin;
using std::endl;
using std::right;
using std::left;
using std::setw;
using std::string;
// MineSweepBoard.h
class MineSweepBoard
{
public:
MineSweepBoard(int rows, int cols, float per);
MineSweepBoard(int rows, int cols);
MineSweepBoard();
virtual ~MineSweepBoard();
static const int ROW_DEFAULT, COL_DEFAULT;
static const float CHANCE_DEFAULT;
static const unsigned char MINE_MASK, UNCOVERED_MASK;
static void Randomize();
void RandomizeBoard();
bool IsMine(int r, int c);
bool IsUncovered(int r, int c);
int UncoverSpace(int r, int c);
int GetAdjMineCount(int r, int c);
bool IsOnBoard(int r, int c);
char GetBoardSquare(int r, int c);
int GetRows();
int GetCols();
float GetPercentage();
int GetMineCount();
int GetSafeCount();
private:
int rowcount, colcount;
int minecount, safecount;
float percentage;
char * board;
bool safedummy;
void Init(int rows, int cols, float per);
};
// MineSweeper.h
class MineSweeper : public MineSweepBoard
{
public:
MineSweeper();
MineSweeper(int rows, int cols, float difficulty);
MineSweeper(int rows, int cols, float difficulty, char mchar, char bchar, char uchar);
static const char MINE_DEFAULT, BLANK_DEFAULT, UNKNOWN_DEFAULT;
void PrintBoard();
char GetCharForSpace(int r, int c);
void Play();
bool WonGame();
private:
char minechar, blankchar, unknownchar;
int cleared;
void Init(char mchar, char bchar, char uchar);
};
// MineSweepBoard.cpp
const int MineSweepBoard::ROW_DEFAULT = 10, MineSweepBoard::COL_DEFAULT = 10;
const float MineSweepBoard::CHANCE_DEFAULT = 0.85;
const unsigned char MineSweepBoard::MINE_MASK = 0x1, MineSweepBoard::UNCOVERED_MASK = 0x2;
void MineSweepBoard::Randomize()
{
srand(time(NULL));
}
int MineSweepBoard::GetRows()
{
return rowcount;
}
int MineSweepBoard::GetCols()
{
return colcount;
}
float MineSweepBoard::GetPercentage()
{
return percentage;
}
int MineSweepBoard::GetMineCount()
{
return minecount;
}
int MineSweepBoard::GetSafeCount()
{
return safecount;
}
MineSweepBoard::MineSweepBoard()
{
Init(ROW_DEFAULT, COL_DEFAULT, CHANCE_DEFAULT);
}
MineSweepBoard::MineSweepBoard(int rows, int cols)
{
Init(rows, cols, CHANCE_DEFAULT);
}
MineSweepBoard::MineSweepBoard(int rows, int cols, float per)
{
Init(rows, cols, per);
}
MineSweepBoard::~MineSweepBoard()
{
delete[] board;
}
void MineSweepBoard::Init(int rows, int cols, float per)
{
minecount = 0;
safecount = rows * cols;
percentage = per;
rowcount = rows;
colcount = cols;
board = new char [rows * cols];
RandomizeBoard();
}
char MineSweepBoard::GetBoardSquare(int r, int c)
{
return board[r * colcount + c];
}
void MineSweepBoard::RandomizeBoard()
{
for (int i = 0, j = rowcount * colcount; i != j; ++i)
{
float r = (((float) rand()) / ((float) RAND_MAX));
board[i] = (percentage < r);
if (board[i]) ++minecount;
}
safecount -= minecount;
}
bool MineSweepBoard::IsOnBoard(int r, int c)
{
return (
(r >= 0 && r < rowcount) &&
(c >= 0 && c < colcount)
);
}
bool MineSweepBoard::IsMine(int r, int c)
{
return (
(IsOnBoard(r, c)) &&
(GetBoardSquare(r, c) & MINE_MASK)
);
}
bool MineSweepBoard::IsUncovered(int r, int c)
{
return (
(IsOnBoard(r, c)) &&
(GetBoardSquare(r, c) & UNCOVERED_MASK)
);
}
int MineSweepBoard::UncoverSpace(int r, int c)
{
int uncovered = 0;
while (IsOnBoard(r, c) && !IsUncovered(r, c))
{
board[r * colcount + c] |= UNCOVERED_MASK;
if (!(GetBoardSquare(r, c) & MINE_MASK)) ++uncovered;
else break;
if (GetAdjMineCount(r, c) == 0)
{
uncovered += UncoverSpace(r + 0, c + 1);
uncovered += UncoverSpace(r + 0, c - 1);
uncovered += UncoverSpace(r + 1, c + 0);
uncovered += UncoverSpace(r - 1, c + 0);
}
break;
}
return uncovered;
}
int MineSweepBoard::GetAdjMineCount(int r, int c)
{
return IsMine(r + 0, c + 1) + IsMine(r + 0, c - 1) +
IsMine(r + 1, c + 0) + IsMine(r - 1, c + 0) +
IsMine(r + 1, c + 1) + IsMine(r - 1, c - 1) +
IsMine(r + 1, c - 1) + IsMine(r - 1, c + 1);
}
// MineSweeper.cpp
const char MineSweeper::MINE_DEFAULT = 'X', MineSweeper::BLANK_DEFAULT = ' ', MineSweeper::UNKNOWN_DEFAULT = '?';
MineSweeper::MineSweeper() : MineSweepBoard()
{
Init(MINE_DEFAULT, BLANK_DEFAULT, UNKNOWN_DEFAULT);
}
MineSweeper::MineSweeper(int rows, int cols, float difficulty) : MineSweepBoard(rows, cols, difficulty)
{
Init(MINE_DEFAULT, BLANK_DEFAULT, UNKNOWN_DEFAULT);
}
MineSweeper::MineSweeper(int rows, int cols, float difficulty, char mchar, char bchar, char uchar) : MineSweepBoard(rows, cols, difficulty)
{
Init(mchar, bchar, uchar);
}
void MineSweeper::Init(char mchar, char bchar, char uchar)
{
minechar = mchar;
blankchar = bchar;
unknownchar = uchar;
}
void MineSweeper::PrintBoard()
{
for (int i = 0; i < GetCols(); ++i) cout << setw(4) << right << i;
cout << left << endl << endl;
for (int r = 0; r < GetCols(); ++r)
{
cout << setw(3) << r;
for (int c = 0; c < GetRows(); ++c)
{
cout << setw(4) << GetCharForSpace(r, c);
}
cout << endl;
}
}
char MineSweeper::GetCharForSpace(int r, int c)
{
if (IsUncovered(r, c))
{
if (IsMine(r, c))
return minechar;
int count = GetAdjMineCount(r, c);
if (count == 0)
return blankchar;
else
return '0' + count;
}
else
return unknownchar;
}
void MineSweeper::Play()
{
int score = 0;
PrintBoard();
cout << "Total Bombs In This Game: " << GetMineCount() << endl;
while (true)
{
string dummy;
int inputrow = -1, inputcol = -1;
cout << "Please Input Your ROW & COLUMN Guess Coordinate (i.e. 3 2): ";
cin >> inputrow >> inputcol;
if (!cin || IsUncovered(inputrow, inputcol) || !IsOnBoard(inputrow, inputcol))
{
cout << "Invalid Selection! ";
if (!cin)
{
cin.clear();
cin >> dummy;
}
continue;
}
int uncovered = UncoverSpace(inputrow, inputcol);
PrintBoard();
if (IsMine(inputrow, inputcol))
{
cout << endl << endl << "\t\tXXXXXX BOMB HIT XXXXXX" << endl << "\t\t\tGame Over." << endl << endl;
break;
}
else
{
score += uncovered;
cleared += uncovered;
if (WonGame())
{
cout << endl << endl << "\t\t------ ALL BOMBS CLEARED ------" << endl << "\t\t\tYou Win!" << endl << endl;
break;
}
}
}
cout << "your Score: " << score << endl;
}
bool MineSweeper::WonGame()
{
return (cleared == GetSafeCount());
}
// main.cpp
int main(int argc, char * argv[])
{
MineSweepBoard::Randomize();
cout << endl << endl << "\t\tWelcome To Wug's Minesweeper" << endl << endl;
while(true)
{
char again = 'n';
MineSweeper m;
m.Play();
cout << endl << "Play Again? (y/n) ";
cin >> again;
if (again == 'y')
{
cout << endl << endl;
continue;
}
else break;
}
return 0;
}
This code exhibits the following traits that your original version did not:
you can win games
as with windows minesweeper, picking a piece in the middle of an empty space clears the whole space
input validation
memory management (yours just used memory on the stack, it didn't have to new and delete anything
inheritance
the indentation is consistent (reading code with inconsistent indentation is not fun)