2

I am trying to make a console version of Minesweeper, but I'm having a bit of difficulity with editing the particular cells on the board. As you can see, I have a Board which has a private [6][6] array of Cell objects.

At the moment, I'm trying to call the Cell methods with something like Board gameBoard; gameBoard.accessCell(row,col).flag(); but this seems to not be actually editing the state of the accessed Cell because the object is being copied over rather than a pointer. How can I fix Board::accessCell(int row, int col) to return a pointer to the object so that I can call a function and actually edit its state?

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <iomanip>
#include <string>
using namespace std;

#define debugging true //set this to true to activiate debugging

const int ROWS(6), COLS(6), MINE(-1);
const char FLAG('F'), REVEALED('R'), HIDDEN('*');

class Cell
{
    friend class Board;
    private:
        char displaySetting;
        int minesTouching;
    public:
        Cell();
        int getMinesTouching() const;
        void increaseMinesTouching();
        char getDisplaySetting() const;
        bool isMine() const;
        void flag();
        void reveal();
        void setMine();
};
int Cell::getMinesTouching() const { return this->minesTouching; }
void Cell::increaseMinesTouching() { this->minesTouching++; }
char Cell::getDisplaySetting() const { return this->displaySetting; }
bool Cell::isMine() const { return this->minesTouching == MINE; }
void Cell::flag() { this->displaySetting = FLAG; }
void Cell::reveal() { this->displaySetting = REVEALED; }
void Cell::setMine() { this->minesTouching = MINE; }
Cell::Cell():
    displaySetting(HIDDEN),
    minesTouching(0)
{}

class Board
{
    private:
        Cell boardCells[ROWS][COLS];
    public:
        Board();
        bool isInBounds(int row, int col) const;
        void reveal(int row, int col);
        void displayBoard() const;
        Cell accessCell(int row, int col) const;
};
Board::Board()
{
    //place mines randomly
    srand(time(0));
    for(int i=0; i<6;)
    {
        int row = rand()%6, col = rand()%6;
        if(!this->boardCells[row][col].isMine())
        {
            this->boardCells[row][col].setMine();
            i++;
        }
    }

    //determine number of mines touching each space and store them
    for(int i=0; i<ROWS; i++)
    {
        for(int j=0; j<COLS; j++)
        {
            if(!boardCells[i][j].isMine())
            {
                if(boardCells[i+1][j+1].isMine())   boardCells[i][j].increaseMinesTouching(); //bottom right
                if(boardCells[i-1][j-1].isMine())   boardCells[i][j].increaseMinesTouching(); //top left
                if(boardCells[i+1][j+0].isMine())   boardCells[i][j].increaseMinesTouching(); //down
                if(boardCells[i+0][j+1].isMine())   boardCells[i][j].increaseMinesTouching(); //right
                if(boardCells[i-1][j-0].isMine())   boardCells[i][j].increaseMinesTouching(); //up
                if(boardCells[i-0][j-1].isMine())   boardCells[i][j].increaseMinesTouching(); //left
                if(boardCells[i+1][j-1].isMine())   boardCells[i][j].increaseMinesTouching(); //bottom left
                if(boardCells[i-1][j+1].isMine())   boardCells[i][j].increaseMinesTouching(); //top right
            }
        }
    }
}
bool Board::isInBounds(int row, int col) const
{
    if(row < 0) return false;
    if(row >= ROWS) return false;
    if(col >= COLS) return false;
    if(col < 0) return false;
    return true;
}
void Board::reveal(int row, int col)
{
    if(!this->boardCells[row][col].getMinesTouching())
    {
        this->boardCells[row][col].reveal();
            if(isInBounds(row+1, col+1))    this->reveal(row+1, col+1); //bottom right
        if(isInBounds(row-1, col-1))    this->reveal(row-1, col-1); //top left
        if(isInBounds(row+1, col+0))    this->reveal(row+1, col+0); //down
        if(isInBounds(row+0, col+1))    this->reveal(row+0, col+1); //right
        if(isInBounds(row-1, col-0))    this->reveal(row-1, col-0); //up
        if(isInBounds(row-0, col-1))    this->reveal(row-0, col-1); //left
        if(isInBounds(row+1, col-1))    this->reveal(row+1, col-1); //bottom left
        if(isInBounds(row-1, col+1))    this->reveal(row-1, col+1); //top right
    }
}
void Board::displayBoard() const
{
    system("clear");
    if(debugging) //display system board if debugging is enabled
    {
        for(int i=0; i<ROWS; i++)
        {
            for(int j=0; j<COLS; j++)
                cout << "[ " << setw(3) << this->boardCells[i][j].getMinesTouching() << setw(3) << " ]";
            cout << "\n";
        }
        cout << "\n\n\n";
    }

    //
    for(int i=0; i<ROWS; i++)
    {
        for(int j=0; j<COLS; j++)
        {
            if(this->boardCells[i][j].getDisplaySetting() == HIDDEN)
                cout << "[ " << setw(3) << this->boardCells[i][j].getDisplaySetting() << setw(3) << " ]";
            else if(this->boardCells[i][j].getDisplaySetting() == REVEALED)
                cout << "[ " << setw(3) << this->boardCells[i][j].getMinesTouching() << setw(3) << " ]";
            else
                cout <<"[ " << setw(3) << FLAG << setw(3) << " ]";
        }
        cout << "\n";
    }
    cout << "\n";
}
Cell Board::accessCell(int row, int col) const { return this->boardCells[row][col]; }

//function prototypes
void provideMenu();
string playTurn(Board gameBoard, int& guesses);
void playGame();

int main()
{
    Board gameBoard;
    provideMenu();
    return 0;
}

void provideMenu()
{
    int choice(0);
    while(choice < 1 || choice > 3)
    {
        cout << "1:\t Play a game of Minesweeper" << endl;
        cout << "2:\t Help" << endl;
        cout << "3:\t Exit" << endl;
        cin>>choice;
    }
    switch(choice)
    {
        case 1:
            playGame();
            break;
        case 2:
            cout << "The objective of Minesweeper is to clear all the tiles on the board without mines without uncovering any hidden mines" << endl;
            cout << "*\t Hidden tile, has yet to be revealed" << endl;
            cout << "F\t Flagged tile, marked by user as possible mine" << endl;
            cout << "#\t Any number represents the number of mines touching the tile" << endl;
            break;
    }
}

void playGame()
{
    Board gameBoard;
    int guesses(0);
    string gameState = "onGoing";
    while(gameState == "onGoing")
    {
        gameState = playTurn(gameBoard, guesses);
        if(gameState == "userWon")
            cout << "Congratulations, you've one!" << endl;
        if(gameState == "userLost")
        {
            cout << "Game over! Try again!" << endl;
            gameBoard.displayBoard();
        }
    }
}

string playTurn(Board gameBoard, int& guesses)
{
    gameBoard.displayBoard();

    int row;
    do
    {
        cout << "Row:";
        cin>>row;
    } while(row <0 || row >= ROWS);

    int col;
    do
    {
        cout << "Column:";
        cin>>col;
    } while(col < 0 || col>= COLS);

    if(gameBoard.accessCell(row, col).isMine())
        return "userLost";
    if(++guesses == ROWS*COLS-6)
        return "userWon";
    gameBoard.reveal(row,col);
    return "onGoing";
}
2
  • This is far too much code for a Stack Overflow question. Please create a much smaller test-case that is representative of your problem. Commented Jul 17, 2012 at 0:13
  • Your constructor calls isMine on objects that don't exist because they're outside the range of the array. Commented Jul 17, 2012 at 0:18

2 Answers 2

4

You have defined your access method to return a copy:

    Cell accessCell(int row, int col) const ;

Since you want to be able to modify the Cell that is returned, you should return a reference instead, and the method should not be const.

    Cell & accessCell(int row, int col);

The corresponding changes need to be done to your implementation of the method also.

Cell & Board::accessCell(int row, int col) { return this->boardCells[row][col]; }
Sign up to request clarification or add additional context in comments.

Comments

0

Return a reference to the Cell object instead of a copy:

const Cell& Board::accessCell(int row, int col) const
{
    return this->boardCells[row][col];
}

If you need a mutable version (non-const), then I will hint to you that you need to overload this function.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.