HashHazard
HashHazard

Reputation: 561

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!

Upvotes: 0

Views: 1918

Answers (2)

Wug
Wug

Reputation: 13196

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)

Upvotes: 1

Software_Designer
Software_Designer

Reputation: 8587

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;

            }
        }
}

Upvotes: 3

Related Questions