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;
}
I am trying to make a little game for a school lab and i got stuck. I know that the code is not the best but a hint about how to solve this problem 1st of all will be awesome :D
I get this :error C2679: binary '[' : no operator found which takes a right-hand operand of type 'overloaded-function' (or there is no acceptable conversion)
at lines 183 and 190. Any ideeas?
#include <iostream>
#include <conio.h>
#include <stdio.h>
#include <ctime>
#include <vector>
#include <string>
using namespace std;
class monstru{
public :
int x;
int y;
monstru(int X, int Y);
int GetX();
void SetX(int);
int GetY();
void SetY(int);
};
monstru::monstru(int X, int Y){
x = X;
y = Y;
}
int monstru::GetX(){
return x;
}
int monstru::GetY(){
return y;
}
void monstru::SetX(int X){
x = X;
}
void monstru::SetY(int Y){
y = Y;
}
class capcana{
public:
int x;
int y;
capcana(int X, int Y);
int GetX();
void SetX(int);
int GetY();
void SetY(int);
};
capcana::capcana(int X, int Y){
x = X;
y = Y;
}
int capcana::GetX(){
return x;
}
int capcana::GetY(){
return y;
}
void capcana::SetX(int X){
x = X;
}
void capcana::SetY(int Y){
y = Y;
}
int Verificare(vector<monstru>& Nmonstru, vector<capcana>& Ncapcana, vector< vector<char> > map);
void AdaugareMonstru(vector<monstru>& monstru);
void AdaugareCapcana(vector<capcana>& Ncapcana);
int main()
{
char player = 'P';
int posX = 1, posY = 1,temp=0;
char treasure = 'X';
//vector<char> map[7][10];
vector< vector<char> > map(7, vector<char>(10));
vector<monstru> M;
vector<capcana> C;
//vector<monstru> B;
AdaugareMonstru(M);
AdaugareCapcana(C);
//Initializing the map
for (int i = 0; i<7; i++){
for (int j = 0; j<10; j++){
map[i][j] = '.';
}
}
//Drawing the Map
for (int i = 0; i<7; i++)
{
for (int j = 0; j<10; j++)
cout << map[i][j] << " ";
cout << endl;
}
while (true)
{
char move;
cin >> move;
switch (move)
{
// move up;
case 'w':
if (posY <= 0)
{
cout << endl;
cout << "Character is going out of the range! Try again";
cout << endl;
cout << endl;
break;
}
else
{
map[posY][posX] = '.';
posY -= 1;
map[posY][posX] = player;
}
break;
// move down;
case 's':
if (posY >= 6)
{
cout << endl;
cout << "Character is going out of the range! Try again";
cout << endl;
cout << endl;
break;
}
else
{
map[posY][posX] = '.';
posY += 1;
map[posY][posX] = player;
}
break;
// move left;
case 'a':
if (posX <= 0)
{
cout << "Character is going out of the range! Try again";
cout << endl;
cout << endl;
}
else
{
map[posY][posX] = '.';
posX -= 1;
map[posY][posX] = player;
}
break;
//move right
case 'd':
if (posX >= 9)
{
cout << "Character is going out of the range! Try again";
cout << endl;
cout << endl;
}
else
{
map[posY][posX] = '.';
posX += 1;
map[posY][posX] = player;
}
break;
}
//Re-drawing the map for each turn
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 10; j++)
cout << map[i][j] << " ";
cout << endl;
}
temp = Verificare(M, C, map);
if (temp != 0)
break;
}
}
int Verificare(vector<monstru>& Nmonstru, vector<capcana>& Ncapcana, vector< vector<char> > map){
int temp;
for (int i = 0; i < 4; i++){
if (map[Nmonstru[i].GetX][Nmonstru[i].GetY] == 'P'){
** I get error here ^^^^ **
** I get error here ^^^^ **
** I get error here ^^^^ **
cout << "Ai fost mancat de monstru! Ai pierdut!";
temp = 1;
}
}
for (int i = 0; i < 4; i++){
if (map[Ncapcana[i].GetX][Ncapcana[i].GetY] == 'P'){
** I get error here ^^^^ **
** I get error here ^^^^ **
** I get error here ^^^^ **
cout << "Ai cazut intr-o capcana! Ai pierdut!";
temp = 2;
}
}
if (map[6][9] == 'P')
{
cout << "Ai gasit comoara! Ai castigat";
temp = 3;
}
}
void AdaugareMonstru(vector<monstru>& Nmonstru){
srand(time(0));
for (int i = 0; i < 4; i++){
monstru newMonstru(rand() % 6, rand() % 9);
Nmonstru.push_back(newMonstru);
}
}
void AdaugareCapcana(vector<capcana>& Ncapcana){
srand(time(0));
for (int i = 0; i < 4; i++){
capcana newCapcana(rand() % 6, rand() % 9);
Ncapcana.push_back(newCapcana);
}
}
GetX and GetY of your class are functions. Not member variables. To call y function you need to add parenthesis (..) behind the function name.
So just add "()" to GetX ad GetY:
if (map[Ncapcana[i].GetX()][Ncapcana[i].GetY()] == 'P'){
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).
Here is the code I have for a programing assignment I have. Im getting this error when I run the program
"Unhandled exception at at 0x772BC41F in STRUCT2.EXE: Microsoft C++ exception: std::out_of_range at memory location 0x0043ED04." If I understand this right, the error means my array has exceeded the allotted memory space. is that correct? and if this is correct, what am I doing wrong? My input file has less than 30 elements in it.
#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cmath>
#include <sstream>
#include <cctype>
using namespace std;
struct Element
{
string Name;
char eN1;
char eN2;
float Weight;
};
struct Formula
{
char Element1;
char ElementA;
int Atom;
};
void ELEMENTS(Element ElmAry[30]);
float Str2Float(string Weight);
void FORMULAS(Formula FormAry[30]);
float CalculateMoleculeWeight(Element ElmAry[30], Formula FormAry[30]);
int main()
{
ifstream inputFile1;
ifstream inputFile2;
ofstream outputFile;
inputFile1.open("Element.txt");
inputFile2.open("Formula.txt");
outputFile.open("Molecular Weight.txt");
Element ElmAry[30];
Formula FormAry[30];
char inputCh;
int i = 0;
string String1;
string mFor;
string ABRV;
int ElmDigit = 0;
float StringWeight = 0;
string Name;
string Weight;
int LENGTH = 0;
float MOLEWT;
if(!inputFile1)
{
cout << "Couldn't find the Element.txt file." << endl;
return 0;
}
if(!inputFile2)
{
cout << "Couldn't find the Formula.txt file." << endl;
return 0;
}
ELEMENTS(ElmAry);
while(inputFile1)
{
Name = String1.substr(0,2);
ElmAry[i].Name = Name;
Weight = String1.substr(3,10);
String1.clear();
StringWeight = Str2Float(Weight);
ElmAry[i].Weight = StringWeight;
i++;
}
i--;
FORMULAS(FormAry);
while (inputFile2)
{
getline(inputFile2,String1);
LENGTH = String1.length();
int j = 0;
int n = 0;
while( j < LENGTH)
{
int pos = 0;
pos = String1.find(')');
while(n < LENGTH)
{
inputCh = String1.at(n);
if(isalpha(inputCh) && isupper(inputCh))
{
FormAry[j].Element1 = String1.at(n);
n++;
inputCh = String1.at(n);
}
if(isalpha(inputCh) && islower(inputCh))
{
FormAry[j].ElementA = String1.at(n);
n++;
inputCh = String1.at(n);
}
if(ispunct(inputCh))
{
n++;
inputCh = String1.at(n);
ElmDigit = (inputCh-'0');
}
if(isdigit(inputCh))
{
FormAry[j].Atom = ElmDigit;
n++;
}
inputCh = String1.at(n);
j++;
if(iscntrl(inputCh))
{
n++;
inputCh = String1.at(n);
j++;
}
n++;
}
}
}
MOLEWT = CalculateMoleculeWeight(ElmAry, FormAry);
cout << "\t\t MOLECULAR WEIGHT CHART \t\t\n" << endl;
cout << "\n| FORMULA |\t " << "\t| ATOM.WT |" << endl;
cout << "_______________________________";
outputFile << "\t\t MOLECULAR WEIGHT CHART \t\t\n" << endl;
outputFile << "\n| FORMULA |\t " << "\t| ATOM.WT |" << endl;
outputFile << "_______________________________";
for (int a = 0; a < 30; a++)
{
cout << MOLEWT << endl;
outputFile << MOLEWT << endl;
}
inputFile1.close();
inputFile2.close();
outputFile.close();
cin.get();
cin.get();
return 0;
}
void ELEMENTS(Element ElmAry[30])
{
for(int i = 0; i < 30; i++)
{
ElmAry[i].Weight = 0;
}
}
void FORMULAS(Formula FormAry[30])
{
for(int x = 0; x < 30; x++)
{
for(int x = 0; x < 9; x++)
{
FormAry[x].Atom = 1;
}
}
}
float Str2Float (string x)
{
stringstream ss(x);
float StringWeight;
ss >> StringWeight;
return StringWeight;
}
float CalculateMoleculeWeight(Element ElmAry[30], Formula FormAry[30])
{
int i;
int j=0;
float MoleWT = 0;
float MoleSum = 0;
char e1;
char e2;
char f1;
char f2;
for(i = 0; i < 30; i++)
{
f1 = FormAry[j].Element1;
f2 = FormAry[j].ElementA;
e1 = ElmAry[i].eN1;
e2 = ElmAry[i].eN1;
if
(e1 == f1 && e2 == f2)
{
MoleWT = ElmAry[i].Weight * FormAry[j].Atom;
MoleSum = MoleSum + MoleWT;
j++;
}
}
return MoleSum;
}
when I get to
while(inputFile1)
{
Name = String1.substr(0,2);
ElmAry[i].Name = Name;
Weight = String1.substr(3,10);//invalid string position
String1.clear();
StringWeight = Str2Float(Weight);
ElmAry[i].Weight = StringWeight;
i++;
}
i--;
Weight = String1.substr(3,10); gives me an invalid string position
std::out_of_range is an exception you get when you attempt to access memory outside the space you've allocated (in an STL container). In this particular case, you are accessing areas of a std::string that has not been allocated:
Weight = String1.substr(3,10); // empty string or string.length() < 4 throws here
std::string::substr takes index parameters that must be within the bounds of the array encapsulated by std::string. If the string is only 2 characters long, and you attempt to get characters starting at the 4th position, you will see the std::out_of_range exception. You should check the length prior to doing this kind of operation.
Additionally, you are declaring your arrays:
Element ElmAry[30];
Formula FormAry[30];
But you are looping through an entire file (which potentially has more than 30 elements). Thus, when i >= 30, you are out of bounds (and behavior will be undefined).
You can fix that by using std::vector, which will allow the array to be dynamically sized, or another collection (e.g. std::list, std::deque).
The problem is simple. I made a 3X3 tictactoe game with 3X3 arrays. But the problem is:
array[0][3] = array[1][0]
Which is strange because first of all, the array I made didn't have a fourth column. So array[0][3] doesn't even exist! And to make matters complicated, it takes the value of [1][0]
I'm having problems when I input co ordinates of my move as: 0 2
void displayBoard(int tictac[3][3])
{
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
cout << tictac[i][j] << " ";
} cout << "\n" ;
} cout << "\n";
}
int Horizontal(int x, int y, int tictac[3][3])
{
if(tictac[x][y+1]==0)
{
tictac[x][y+1]=2;
return 1;
}
if(tictac[x][y-1]==0)
{
tictac[x][y-1]=2;
return 1;
}
if(tictac[x][y-2]==0)
{
tictac[x][y-2]=2;
return 1;
}
if(tictac[x][y+2]==0)
{
tictac[x][y+2]=2;
return 1;
}
return 0;
}
int Vertical(int x, int y, int tictac[3][3])
{
if(tictac[x+1][y]==0)
{
tictac[x+1][y]=2;
return 1;
}
if(tictac[x-1][y]==0)
{
tictac[x-1][y]=2;
return 1;
}
if(tictac[x-2][y]==0)
{
tictac[x-2][y]=2;
return 1;
}
if(tictac[x+2][y]==0)
{
tictac[x+2][y]=2;
return 1;
}
return 0;
}
void AI(int X,int Y,int tictac[3][3])
{
int done = 0;
cout << "\n-------------------------\nComputer plays: \n";
done = Horizontal(X,Y,tictac);
if(done == 0)
{
done = Vertical(X,Y,tictac);
}
}
int main()
{
int tictac[3][3] = {{0,0,0},{0,0,0}, {0,0,0} };
int X, Y;
for(int r=1; r<100; r++)
{
cout << "\n-------------------------\nPlayer play a move: \n";
cin >> X;
cin >> Y;
if(tictac[X][Y]==0)
{
tictac[X][Y] = 1;
displayBoard(tictac);
AI(X,Y,tictac);
displayBoard(tictac);
}
else
{
cout << "Space occupied. Try different cell." << endl;
}
}
}
You need to add bounds checking. For instance when the user inputs the move coordinates you need to ensure they are within the range of 0 to 2. The example below validates the input to ensure only numbers are entered, that both X and Y coordinates are entered on a single line and that the coordinates are within range. It uses std::stringstream to parse the coordinates instead of having to deal with checking and clearing the fail bits on std::cin
#include <string> // at top of your .cpp file
#include <sstream>
// in main()
// Get en entire input line so we can skip extra characters
// after the cell coordinates
string inputLine;
std::getline(cin, inputLine);
stringstream inputStream(inputLine);
if(!(inputStream >> X) || !(inputStream >> Y))
{
cout << "Please enter the cell coordinates in the form of # #" << endl;
continue;
}
bool invalidCoordinates = false;
if(X < 0 || X > 2)
{
cout << "invalid X location" << endl;
invalidCoordinates = true;
}
if(Y < 0 || Y > 2)
{
cout << "invalid Y location" << endl;
invalidCoordinates = true;
}
// check for invalid input
if(invalidCoordinates) continue;
You also need to do the same thing in your Vertical and Horizontal functions when checking if a valid move is possible. For instance if x is 2 and y is 2 the following lines from Vertical will access data outside the bounds of the array.
if(tictac[x+1][y]==0)
{
tictac[x+1][y]=2;
return 1;
}
This is because you are actually accessing the forth element with x+1. This element technically doesn't exist but with a multi-dimensional array you end up accessing tictac[0][y+1] instead.
You can get around the bounds checking in Vertical and Horizontal by adding some padding around the edges and fill them with a value that indicates they are unusable. In your case increase the size by 3 in each direction.
int tictac[9][9] = {
{3,3,3,3,3,3,3,3,3},
{3,3,3,3,3,3,3,3,3},
{3,3,3,3,3,3,3,3,3},
{3,3,3,0,0,0,3,3,3},
{3,3,3,0,0,0,3,3,3},
{3,3,3,0,0,0,3,3,3},
{3,3,3,3,3,3,3,3,3},
{3,3,3,3,3,3,3,3,3},
{3,3,3,3,3,3,3,3,3},
};
You will need to make adjustments to X and Y appropriately so they point to the correct location.
X += 3; // Adjust for padding
Y += 3; // Adjust for padding
if(tictac[X][Y]==0)
{
tictac[X][Y] = 1;
displayBoard(tictac);
AI(X,Y,tictac);
displayBoard(tictac);
}
You may need to make adjustments in other parts of your code but the above example should get your started.
There is also a problem in your displayBoard function. When it prints out the elements of the array i and j are reversed so the board appears rotated 90 degrees. Change the following line
cout << tictac[i][j] << " ";
to
cout << tictac[j][i] << " ";
Another problem is that you are using \n at the end of each line you output without using std::flush to ensure the line is sent to the console. You can either put << flush; after those lines or remove the \n and put << endl; at the end of the line.
cout << "\n-------------------------\nComputer plays: \n" << flush;
or
cout << "\n-------------------------\nComputer plays: " << endl;
The code below is a complete update of the original code included in your question. It incorporates the above suggestions and makes a couple of other changes. I've also added an endgame check to determine if there are any moves left.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
static const int BoardSize = 3;
static const int BoardPadding = BoardSize;
static const int ArraySize = BoardSize + (BoardPadding * 2);
void displayBoard(int tictac[ArraySize][ArraySize])
{
for(int y = 0; y < BoardSize; y++)
{
for(int x = 0; x < BoardSize; x++)
{
cout << tictac[BoardPadding + x][BoardPadding + y] << " ";
}
cout << endl ;
}
cout << endl;
}
int Horizontal(int x, int y, int tictac[ArraySize][ArraySize])
{
if(tictac[x][y+1]==0)
{
tictac[x][y+1]=2;
return 1;
}
if(tictac[x][y-1]==0)
{
tictac[x][y-1]=2;
return 1;
}
if(tictac[x][y-2]==0)
{
tictac[x][y-2]=2;
return 1;
}
if(tictac[x][y+2]==0)
{
tictac[x][y+2]=2;
return 1;
}
return 0;
}
int Vertical(int x, int y, int tictac[ArraySize][ArraySize])
{
if(tictac[x+1][y]==0)
{
tictac[x+1][y]=2;
return 1;
}
if(tictac[x-1][y]==0)
{
tictac[x-1][y]=2;
return 1;
}
if(tictac[x-2][y]==0)
{
tictac[x-2][y]=2;
return 1;
}
if(tictac[x+2][y]==0)
{
tictac[x+2][y]=2;
return 1;
}
return 0;
}
void AI(int X,int Y,int tictac[ArraySize][ArraySize])
{
int done = 0;
cout << "\n-------------------------\nComputer plays: " << endl;
done = Horizontal(X,Y,tictac);
if(done == 0)
{
done = Vertical(X,Y,tictac);
}
}
// Check if all moves have been made
bool isEndGame(int tictac[ArraySize][ArraySize])
{
int count = 0;
for(int y = 0; y < BoardSize; y++)
{
for(int x = 0; x < BoardSize; x++)
{
count += tictac[BoardPadding + x][BoardPadding + y] ? 1 : 0;
}
}
return count == (BoardSize * BoardSize);
}
int main()
{
int tictac[ArraySize][ArraySize] = {
{3,3,3,3,3,3,3,3,3},
{3,3,3,3,3,3,3,3,3},
{3,3,3,3,3,3,3,3,3},
{3,3,3,0,0,0,3,3,3},
{3,3,3,0,0,0,3,3,3},
{3,3,3,0,0,0,3,3,3},
{3,3,3,3,3,3,3,3,3},
{3,3,3,3,3,3,3,3,3},
{3,3,3,3,3,3,3,3,3},
};
int X, Y;
while(isEndGame(tictac) == false)
{
cout << "\n-------------------------\nPlayer play a move: " << flush;
// Get en entire input line so we can skip extra characters
// after the cell coordinates
string inputLine;
std::getline(cin, inputLine);
stringstream inputStream(inputLine);
if(!(inputStream >> X) || !(inputStream >> Y))
{
cout << "Please enter the cell coordinates in the form of # #" << endl;
continue;
}
bool invalidCoordinates = false;
if(X < 0 || X >= BoardSize)
{
cout << "invalid X location" << endl;
invalidCoordinates = true;
}
if(Y < 0 || Y >= BoardSize)
{
cout << "invalid Y location" << endl;
invalidCoordinates = true;
}
// check for invalid input
if(invalidCoordinates) continue;
// adjust the coordinates and do our thing
X += BoardPadding;
Y += BoardPadding;
if(tictac[X][Y]==0)
{
tictac[X][Y] = 1;
displayBoard(tictac);
AI(X,Y,tictac);
displayBoard(tictac);
}
else
{
cout << "Space occupied. Try different cell." << endl;
}
}
cout << "game finished...check for winner" << endl;
}
Note: It's a bad idea to use using namespace std;. It pulls everything from the std namespace into the current scope (in this case the global namespace) and can cause conflicts. It's best to use fully qualified names such as std::cout instead to avoid this.
In case of this array
int array[3][3];
the following statement is valid
array[0][3] == array[1][0]
because:
C/C++ does not perform any boundary checks.
3x3 array is stored as a 1D array. When you specify the 2D indices, the compiler transforms them to 1D index: [j][i] becomes [j * width + i].
Thus, array[0][3] points to 0 * 3 + 3 (third) cell in a memory, but array[1][0] points to 1 * 3 + 0 (also third!) cell of the memory, starting from the start of your 2D array.