Error with array displaying - c++

int move_player() {
if (GetAsyncKeyState(VK_RIGHT) && current_x<max_x) {
int old_x = current_x;
int new_x = current_x+1;
path[old_x] = '_';
path[new_x] = player;
system("cls");
cout << endl;
for (int a=0; a <= 9; a++) {
cout << path[a];
}
} else if (GetAsyncKeyState(VK_LEFT) && current_x>min_x) {
int old_x = current_x;
int new_x = current_x-1;
path[old_x] = '_';
path[new_x]=player;
system("cls");
cout << endl;
for (int b = 0; b <= 9; b++) {
cout << path[b];
}
}
return current_x;
}
What the bulk of code does is it just moves around an object (only right or left). It starts by showing the object on the far left and then I can move it right once but after it just does nothing when I press the right or left key.
How can I solve it?

How can I solve it?
You'll need to use a while loop around the if-else block.
or
call move_player in a while loop in the calling function.

Related

C++ 2d array duplication error in game

I'm new to C++ and I'm trying to figure out why I get two "*" symbols in my game board when I'm moving around. The game is supposed to be about avoiding the troll (#). But I am getting duplicate # and * symbols, and I can't figure out why. It seems that the problem is either in one of the for loops or in the posX or posY variables, which I found out by commenting out segments of the code:
#include <iostream>
#include <string>
using namespace std;
void ClearScreen()
{
cout << string(100, '\n');
}
main()
{
int size_arrx = 10;
int size_arry = 20;
int posX = 0;
int posY = 0;
int trollX = size_arrx - 1;
int trollY = size_arry - 1;
char a[size_arry][size_arrx];
bool Alive = true;
char player = '*';
char troll = '#';
while (Alive == true) {
ClearScreen();
for (int i = 0; i<size_arrx; i++)
{
for (int j = 0; j<size_arry; j++)
{
a[i][j] = 'x';
}
}
for (int i = 0; i<size_arrx; i++)
{
for (int j = 0; j<size_arry; j++)
{
a[posX][posY] = player;
a[trollX][trollY] = troll;
cout << a[i][j];
if (posX< 0) {
a[posX = 0][posY] = player;
cout << a[i][j];
}
else if (posY< 0) {
a[posX][posY = 0] = player;
cout << a[i][j];
}
else if (posY > size_arry - 1) {
a[posX][posY = size_arry - 1] = player;
cout << a[i][j];
}
else if (posX > size_arrx - 1) {
a[posX = size_arrx - 1][posY] = player;
cout << a[i][j];
}
}
cout << endl;
}
char dir;
cin >> dir;
if (dir == 'w') {
trollX++;
posX--;
}
if (dir == 's') {
trollX--;
posX++;
}
if (dir == 'd') {
trollY--;
posY++;
}
if (dir == 'a') {
trollY++;
posY--;
}
}
if ((trollX == posX) && (trollY == posY)) {
Alive == false;
}
}
The result looks like this. I only want one *. The * can move perfectly fine, but a duplicate * follows the original * but 11 X's away.
xxxxxxxxxx*xxxxxxxxx <---- This is a duplicate *
*xxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxx#
xxxxxxxxx#xxxxxxxxxx <---- This is a duplicate #
Thanks in advance if you can help me
for (int i=0;i<size_arrx;i++){
for (int j=0;j<size_arry;j++){
a[i][j]='x';
}
}
a[posX][posY]=player;
a[trollX][trollY]=troll;
for (int i=0;i<size_arrx;i++){
for (int j=0;j<size_arry;j++){
cout << a[i][j];
Using this code gave the same error. I'm interpreting this as a[i][j]='x' populates all positions of a[][] with X's. a[posX][posY]=player; overwrites the position of the player with an * (could be x 2 y 5 for example) and then the board gets printed by cout << a[i][j];. I don't understand how a duplicate symbol gets thrown in there.
Let's simplify your program.
Initialize the board outside of the while loop.
There should be no reason to keep initializing it:
for (unsigned int row = 0; row < size_arry; ++row)
{
std::fill(&a[row][0], &a[row][size_arrx], 'x'); // Fill a row.
}
Printing the board should be simple:
for (unsigned int row = 0; row < size_arry; ++row)
{
for (unsigned int column = 0; column < size_arrx; ++column)
{
cout << a[row][column];
}
cout << '\n';
}
Now the character logic.
Every character has a position, row and column, of where it is. To ease restoration, every character should have a previous position also.
struct Position
{
unsigned int row;
unsigned int column;
};
Sorry about that code, the fingers and keyboard are not cooperating.
To move a character to a valid new position, you have to restore the previous position:
unsigned int player_now_x;
unsigned int player_now_y;
unsigned int player_prev_x;
unsigned int player_prev_y;
//...
a[player_prev_y][player_prev_x] = 'x';
a[player_now_y][player_now_y] = player;
For processing single letter commands, a switch statement may be more readable:
// Update previous position.
player_prev_x = player_now_x;
player_prev_y = player_now_y;
switch (dir)
{
case 'd':
if (player_now_y < size_arry)
{
++player_now_y;
}
break;
case 's':
if (player_now_x < size_arrx)
{
++player_now_x;
}
break;
// ...
}
Simplifications.
You can print the board with one cout if you add an extra column. The ending column of each row (except the last) will have a line ending character, '\n'. The last column of the last row will have a termination character, '\0'.
struct Board
{
void set_player(const Position& pos, char player_token)
{
a[pos.x][pos.y] = player_token;
}
void move_player(const Position& new_position,
const Position& previous_position,
char player_token)
{
set_player(previous_position, 'x');
set_player(new_position, player_token);
}
void print()
{
std::cout << &a[0][0] << "\n";
}
Board()
{
for (unsigned int y = 0; y < size_arry; ++y)
{
std::fill(&a[y][0], &a[y][size_arrx], 'x');
a[y][size_arrx - 1] = '\n';
}
a[size_arry - 1][size_arrx - 1] = '\0';
}
};
//...
Board b;
Position player_now;
Position player_prev;
const char player_token = '*';
//...
switch (dir)
{
case 'd':
if (player_now.y < size_arry)
{
++player_now.y;
}
//...
}
b.move_player(player_now, player_previous, player_token);
Sorry again, for the above code fragment, it's the fingers typing out what they want.

Running two loops at the same time ? moving and traveling using loops

I am a first year Computer Engineer so I am a little bit amatuer in coding C++, anyway I am creating a game where there are two spaceships shooting each other. I currently succeeded making the first spaceship move by using a while loop and the GetASyncKeyState function. but now I am making the bullets travel. I used for loop, and I did succeed in making the bullet travel upward. But there's a problem, I can't move the spaceship until the for loop stop or the bullet reach the top of the console window (I am using console btw). is there a way to both run the for loop and while at the same time ? or to run two different function at the same time since GameMovement() is for the movement of spaceship and BulletTravel() is for the bullet. and I am calling BulletTravel() from GameMovement().
void GameMovements()
{
bool FirstInitialization = true;
int Player1XCoordinate = 55, Player2XCoordinate = 55;
int Player1YCoordinateU = 28, Player1YCoordinateD = 29;
while (true)
{
BulletPattern(Player1XCoordinate);
if (FirstInitialization == true)
{
GameBorderAndStatus();
SetCoordinate(Player1XCoordinate, Player1YCoordinateU);
cout << " ^ \n";
SetCoordinate(Player1XCoordinate, Player1YCoordinateD);
cout << "^==|==^ \n";
FirstInitialization = false;
}
//MOVEMENTS FOR PLAYER 1
else if (GetAsyncKeyState(VK_LEFT) && Player1XCoordinate != 16)
{
system("cls");
GameBorderAndStatus();
Sleep(10);
Player1XCoordinate -= 3;
SetCoordinate(Player1XCoordinate, Player1YCoordinateU);
cout << " ^ \n";
SetCoordinate(Player1XCoordinate, Player1YCoordinateD);
cout << "^==|==^ \n";
}
else if (GetAsyncKeyState(VK_RIGHT) && Player1XCoordinate != 94)
{
system("cls");
GameBorderAndStatus();
Player1XCoordinate += 3;
Sleep(10);
SetCoordinate(Player1XCoordinate, Player1YCoordinateU);
cout << " ^ \n";
SetCoordinate(Player1XCoordinate, Player1YCoordinateD);
cout << "^==|==^ \n";
}
else if (GetAsyncKeyState(VK_UP) && Player1YCoordinateU != 24)
{
system("cls");
GameBorderAndStatus();
Player1YCoordinateU -= 2;
Player1YCoordinateD -= 2;
Sleep(10);
SetCoordinate(Player1XCoordinate, Player1YCoordinateU);
cout << " ^ \n";
SetCoordinate(Player1XCoordinate, Player1YCoordinateD);
cout << "^==|==^ \n";
}
else if (GetAsyncKeyState(VK_DOWN) && Player1YCoordinateU != 28)
{
system("cls");
GameBorderAndStatus();
Player1YCoordinateU += 2;
Player1YCoordinateD += 2;
Sleep(10);
SetCoordinate(Player1XCoordinate, Player1YCoordinateU);
cout << " ^ \n";
SetCoordinate(Player1XCoordinate, Player1YCoordinateD);
cout << "^==|==^ \n";
}
}
}
void GameBorderAndStatus()
{
//Draw game border
for (int i = 0; i < 31; i++)
{
SetCoordinate(15, i);
cout << "|";
SetCoordinate(104, i);
cout << "|";
}
}
void BulletPattern(int Player1MuzzleLocation)
{
for (int i = 25; i != 3; i--)
{
Sleep(100);
SetCoordinate(Player1MuzzleLocation + 3, i);
}
}
void SetCoordinate(int CoordinateX, int CoordinateY)
{
COORD Coordinate;
Coordinate.X = CoordinateX;
Coordinate.Y = CoordinateY;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Coordinate);
}
Rather than using two different functions and moving one object within each, you might find better results keeping track of where each object should be, and using one function to draw both.
It's a little hard to tell what's going on in your code since some functions and variable declarations are missing (I don't see you ever actually drawing a bullet, for example - might be a bug in your BulletPattern?), but something like this might do the trick:
void GameMovements()
{
while (true)
{
//MOVEMENTS FOR PLAYER 1
if (GetAsyncKeyState(VK_LEFT) && Player1XCoordinate != GAMEBOARD_LEFT)
{
Player1XCoordinate -= 3;
}
else if (GetAsyncKeyState(VK_RIGHT) && Player1XCoordinate != GAMEBOARD_RIGHT)
{
Player1XCoordinate += 3;
}
else if (GetAsyncKeyState(VK_UP) && Player1YCoordinate != SPACESHIP_TOP)
{
Player1YCoordinate -= 2;
}
else if (GetAsyncKeyState(VK_DOWN) && Player1YCoordinate != SPACESHIP_BOTTOM)
{
Player1YCoordinate += 2;
}
Sleep(10);
UpdateBulletPosition();
DrawObjects();
}
}
void UpdateBulletPosition()
{
//if the bullet hits the top of the screen, remove it
if (bulletYCoordinate == GAMEBOARD_TOP)
{
bulletXCoordinate = 0;
bulletYCoordinate = 0;
}
//I assume you're automatically generating bullets whenever possible; you'll have to adjust this conditional if that's not the case
//no bullet? generate one
if (bulletXCoordinate == 0)
{
bulletXCoordinate = Player1XCoordinate + 3;
bulletYCoordinate = 25;
}
else
{
bulletYCoordinate--;
Sleep(100);
}
}
void DrawObjects()
{
//wipe the screen and show status first
system("cls");
GameBorderAndStatus();
SetCoordinate(Player1XCoordinate, Player1YCoordinate);
cout << " ^ \n";
SetCoordinate(Player1XCoordinate, Player1YCoordinate + 1);
cout << "^==|==^ \n";
//only draw the bullet if there's a bullet there to draw
if (bulletXCoordinate != 0)
{
SetCoordinate(bulletXCoordinate, bulletYCoordinate);
cout << ".\n";
}
}
const int GAMEBOARD_LEFT = 16;
const int GAMEBOARD_RIGHT = 94;
const int GAMEBOARD_TOP = 3;
const int SPACESHIP_TOP = 24;
const int SPACESHIP_BOTTOM = 28;
int Player1XCoordinate = 55, Player2XCoordinate = 55;
int Player1YCoordinate = 28;
int bulletXCoordinate = 0, bulletYCoordinate = 0;
I also made some tweaks to the rest of your code. Every case in your if-else block used the same basic drawing code, so I pulled that out of the if-else entirely. That also let me drop the entire initialization if-else.
I also dropped one of your vertical coordinates for the spaceship. You really don't need two; just keep track of the upper coordinate and draw the lower half of the ship at Player1YCoordinate + 1.
Finally, I replaced your hardcoded board edges with constants. Magic numbers are generally frowned upon; using named constants makes it easier to determine why you're using a given value in a given location, as well as making it easier to update the code in the future (perhaps you need to update for a different console size).

Error C2440, Battleship C++

My compiler is telling me that I have an error, but I've e-mailed my instructor and he says my code is perfectly fine.
The error is Error:
1 error C4716: 'ShipPlacement' : must return a value, line 139
I'm unsure as to where I went wrong exactly so I'm going to share my code for ShipPlacement:
ShipPlacement(Coord grid[10][10])
{
CoordAndBearing SetBowAndDirection();
CoordAndBearing cab;
cab = SetBowAndDirection();
int start;
if((cab.dir == 3) || (cab.dir == 1)) // GOING HORIZONTAL //
{
if (cab.dir == 3)
start = cab.bx;
else
start = cab.bx - 4;
for(int i = start; i <= start + 4; i = i + 1)
{
grid[i][cab.by].isShip = true;
}
}
else // GOING VERTICAL
{
if(cab.dir == 0)
start = cab.by;
else
start = cab.by - 4;
for (int i = start; i <=start + 4; i = i + 1)
{
grid[cab.bx][i].isShip = true;
}
}
}
And here is my int main:
int main()
{
srand((unsigned int) time (NULL));
void ShipPlacement(Coord grid[10][10]);
Coord grid[10][10];
SetGridParameters(grid);
ShipPlacement(grid);
int ammo = 18;
int hits = 0;
while (hits < 5 && ammo >0 )
{
int x;
int y;
DisplayGrid(grid);
cout << "Ammo left = " << ammo << endl;
cout << "Enter Coord: " << endl;
cin >> x >> y;
ammo= ammo - 1;
if (grid [x][y].isShip == true)
{
hits = hits + 1;
}
else
{
cout << " You missed... " << endl;
}
}
DisplayGrid(grid);
if(hits == 5 )
{
cout << "You sunk the U.S.S McCall!!";
}
else
{
cout << " You lost ";
}
system("pause");
return 0;
}
You've defined the ShipPlacement function without a return type. Some (most?) compilers will issue a warning stating they're assuming it returns an int, followed by an error since it doesn't.
Just explicitly define it as "returning" void (i.e., void ShipPlacement(Coord grid[10][10])), and you should be fine.

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).

Stupid behavior of multi dimensional array

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.