0

I am doing an assignment where we have to make a sliding tile puzzle. The issue is that my print method for printing the game board is outputting the memory address of my 2D array instead of the actual values, but I have no idea how to fix this. I've tried looking up solutions and all I can find is stuff about vectors which I'm not allowed to use.

code from driver.cpp:

#include <iostream>
#include <conio.h>
#include "Specification.h"
#include <windows.h>    //For color in PrintBoard()
using namespace std;

// direction codes (part of the slideTile() interface)
#define SLIDE_UP        1       // pass to slideTile() to trigger UP movement
#define SLIDE_DOWN      2       // pass to slideTile() to trigger DOWN movement
#define SLIDE_LEFT      3       // pass to slideTile() to trigger LEFT movement
#define SLIDE_RIGHT     4       // pass to slideTile() to trigger RIGHT movement

int main() {
    int tempHeight;
    int tempWidth;
    // instantiate the class
    cout << "Please enter the height for the board: ";
    cin >> tempHeight;

    cout << "Please enter the width for the board: ";
    cin >> tempWidth;

    bool exit = false;

    SlidingPuzzle somePuzzle(tempHeight, tempWidth);
    
    char keyStroke = ' ';
    somePuzzle.isBoardSolved();

    cout << "Press any key to begin..." << endl;
    _getch();

    cout << endl << "Scrambling the tiles..." << endl;
    somePuzzle.ScrambleBoard();
    cout << "Scrambling complete, press any key to begin solving." << endl;
    _getch();
    somePuzzle.isBoardSolved();
    do {
        cout << endl << "(w = Up, s = Down, a = Left, d = Right, e = Exit Game)" << endl;
        cout << "Which way to slide?" << endl;
        keyStroke = _getch(); //sets the key used to continue as the move, keys that aren't options do nothing
        switch (keyStroke) {
        case 'w':
        {
            somePuzzle.SlideTile(SLIDE_UP);
            break;
        }
        case 's':
        {
            somePuzzle.SlideTile(SLIDE_DOWN);
            break;
        }
        case 'a':
        {
            somePuzzle.SlideTile(SLIDE_LEFT);
            break;
        }
        case 'd':
        {
            somePuzzle.SlideTile(SLIDE_RIGHT);
            break;
        }
        case 'e':
        {
            exit = true;
            somePuzzle.~SlidingPuzzle();
            break;
        }
        }
    } while (!somePuzzle.isBoardSolved() || !exit);
    // Exit

    _getch();
    return 0;
}

code from specification.h:

#ifndef __SlidingPuzzle__
#define __SlidingPuzzle__

#include <iostream>
#include <windows.h>    //For color in PrintBoard()
using namespace std;

// CLASS SlidingPuzzle
class SlidingPuzzle {
private:
    int height;
    int width;
    int** theBoard;
    int** solvedBoard;
    HANDLE currentConsoleHandle;

    void cls(HANDLE);
public:
    // CONSTRUCTOR
    SlidingPuzzle();        //Gives default values to the SlidingPuzzle's attributes
    SlidingPuzzle(int, int);

    //Deconstructor
    ~SlidingPuzzle();

    //Getter
    int getHeight();
    int getWidth();
    int** getTheBoard();
    int** getSolvedBoard();

    //Methods
    void InitializeBoard();
    bool isBoardSolved();
    bool SlideTile(int);
    void ScrambleBoard();
    void PrintBoard();
}; // end - SlidingPuzzle
#endif

code from implementation.cpp:

#include "Specification.h"

// CONSTRUCTOR
SlidingPuzzle::SlidingPuzzle() {
    this->height = 0;
    this->width = 0;
    this->theBoard = NULL;
    this->solvedBoard = NULL;
    this->currentConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
}
// Overload
SlidingPuzzle::SlidingPuzzle(int newWidth, int newHeight) {
    this->currentConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    if (newHeight > 0) {
        this->height = newHeight;
    }
    else {
        this->height = 0;
    }
    if (newWidth > 0) {
        this->width = newWidth;
    }
    else {
        this->width = 0;
    }

    this->theBoard = new int* [this->height];
    for (int i = 0; i < this->height; i++) {
        this->theBoard[i] = new int[this->width];
    }

    this->solvedBoard = new int* [this->height];
    for (int i = 0; i < this->height; i++) {
        this->solvedBoard[i] = new int [this->width];
    }
}

//Getters
int SlidingPuzzle::getHeight() {
    return this->height;
}

int SlidingPuzzle::getWidth() {
    return this->width;
}

int** SlidingPuzzle::getTheBoard() {
    return this->theBoard;
}

int** SlidingPuzzle::getSolvedBoard() {
    return this->solvedBoard;
}

//Deconstructor
SlidingPuzzle::~SlidingPuzzle() {
    for (int i = 0; i < this->height; ++i)
        delete[] this->theBoard[i];
    delete[] this->theBoard;
}

//Methods
void SlidingPuzzle::InitializeBoard() {
    for (int i = 0; i < this->height; i++) {
        for (int j = 0; j < this->width; j++) {
            if (i == 0) {
                this->theBoard[i][j] = i + j + 1;
            }
            else if (i == 1) {
                this->theBoard[i][j] = i + j + 3;
            }
            else {
                this->theBoard[i][j] = i + j + 5;
                if (this->theBoard[i][j] == (this->width * this->height)) {
                    this->theBoard[i][j] = -1;
                }
            }
        }
    }
}

bool SlidingPuzzle::isBoardSolved() {
    this->cls(currentConsoleHandle);
    this->PrintBoard();

    int correct = 0;

    //Checks each position to see if the are identical
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            if (this->theBoard[i][j] != this->solvedBoard[i][j]) {
                correct = 1;
            }
        }
    }

    if (correct == 0) {
        cout << "isBoardSolved(): true" << endl;
        return true;
    }
    else {
        cout << "isBoardSolved(): false" << endl;
        return false;
    }
}

bool SlidingPuzzle::SlideTile(int directionCode) {
    int row = 0;
    int col = 0;
    int rowSpace = 0;
    int colSpace = 0;

    //Finds the pivot space
    for (int i = 0; i < height; ++i) {
        for (int j = 0; j < width; ++j) {
            if (this->theBoard[i][j] == -1) {
                row = i;
                col = j;
            }
        }
    }

    switch (directionCode) {
        case 1:
        {
            rowSpace = row - 1;
            colSpace = col;
            break;
        }
        case 2:
        {
            rowSpace = row + 1;
            colSpace = col;
            break;
        }
        case 3:
        {
            rowSpace = row;
            colSpace = col - 1;
            break;
        }
        case 4:
        {
            rowSpace = row;
            colSpace = col + 1;
            break;
        }
    }

    //Ensures that the program doesn't break from trying to move off the board
    if (rowSpace >= 0 && rowSpace < height && colSpace >= 0 && colSpace < width) {
        this->theBoard[row][col] = this->theBoard[rowSpace][colSpace];
        this->theBoard[rowSpace][colSpace] = -1;
    }

    return false;
}

void SlidingPuzzle::ScrambleBoard() {
    for (int i = 0; i < 10000; i++) {
        int move = (rand() % 4);
        move++; //Add 1 so the variable matches the values for the directions
        this->SlideTile(move);
    }
}

void SlidingPuzzle::PrintBoard() {  //Refuses to print, no clue why
    HANDLE hConsole;
    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            if (this->theBoard[i][j] == -1) {
                cout << " *";
            }
            else {
                if (this->theBoard[i][j] == this->solvedBoard[i][j]) {
                    SetConsoleTextAttribute(hConsole, 2); //changes the color to green for correct postion
                    cout << " " << this->theBoard[i][j];
                    SetConsoleTextAttribute(hConsole, 15); //reverts color to normal
                }
                else {
                    SetConsoleTextAttribute(hConsole, 4); //changes the color to red for incorrect postion
                    cout << " " << this->theBoard[i][j];
                    SetConsoleTextAttribute(hConsole, 15); //reverts color to normal
                }
            }
        }
        cout << endl;
    }
}

void SlidingPuzzle::cls(HANDLE hConsole)
{
    COORD coordScreen = { 0, 0 };    /* here's where we'll home the
                                     cursor */
    BOOL bSuccess;
    DWORD cCharsWritten;
    CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
    DWORD dwConSize;                 /* number of character cells in
                                     the current buffer */

                                     /* get the number of character cells in the current buffer */

    bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);
    dwConSize = csbi.dwSize.X * csbi.dwSize.Y;

    /* fill the entire screen with blanks */
    bSuccess = FillConsoleOutputCharacter(hConsole, (TCHAR)' ',
        dwConSize, coordScreen, &cCharsWritten);

    /* get the current text attribute */
    bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);

    /* now set the buffer's attributes accordingly */
    bSuccess = FillConsoleOutputAttribute(hConsole, csbi.wAttributes,
        dwConSize, coordScreen, &cCharsWritten);

    /* put the cursor at (0, 0) */
    bSuccess = SetConsoleCursorPosition(hConsole, coordScreen);
}

I have used the suggestions from the comments and now I am finally getting the array to display. However the values in the array are still displaying as memory addresses. I updated the code here to reflect the changes made so far.

Ken White
  • 123,280
  • 14
  • 225
  • 444
  • 2
    How is `theBoard` declared? Can you put together a [mcve]? – Retired Ninja Apr 04 '21 at 19:25
  • `setHeight` returns `bool`. So `this->height = setHeight(newHeight);` sets `this->height` to either 0 or 1, but not to `newHeight` – Igor Tandetnik Apr 04 '21 at 22:29
  • Ok, so changing the height like you said now shows the game board and the pivot point that you move around on the game board in the output, but all the rest of the places are -842150451 which I'm guessing is the memory address? – DeathAngle0 Apr 04 '21 at 22:39
  • If you look at that value as hex is it 0xcdcdcdcd which is used in the debug heap to mark uninitialized heap memory. You've allocated heap memory but not initialized or assigned it any value. https://stackoverflow.com/a/127404/920069 – Retired Ninja Apr 04 '21 at 23:56
  • Too much code. Please provide a [mre] that demonstrates the issue. It's unreasonable to expect us to wade through all of that code trying to figure out what is wrong. Note the word **minimal** in [mre]. – Ken White Apr 05 '21 at 00:04
  • So my InitializeBoard() somehow doesn't provide the 2D array with any values except the -1 that is set when 2Darray position is equal to the width * height? I am really confused how the rest of the values are not being initialized since the -1 is getting set. – DeathAngle0 Apr 05 '21 at 00:05
  • I can see that the code is a bit messy, you don't need to write 'this' each time. I strongly suggest reading about smart pointers from C++11 (unique_ptr and shared_ptr), which allow you to avoid raw pointers. Also, you may consider using std::vector. There is obviously nothing wrong in using raw pointers themselves, but they might be a source of bugs and memory leaks, it's worth learning about newer C++ features. – Maras Apr 05 '21 at 00:06
  • You don't call InitializeBoard() at all as far as I can see. That is the issue. The values in the arrays allocated in the constructor are not initialized - they are not set to any value, thus they can have any random value. You need to either call it after the constructor or in the constructor itself. – Maras Apr 05 '21 at 00:12
  • Also, the ~SlidingPuzzle() is usually called a destructor, not deconstructor ;) – Maras Apr 05 '21 at 00:19

1 Answers1

0

I forgot to add somePuzzle.InitializeBoard(); to the driver.cpp and I feel like a goof now. Thank you all for helping me and sorry about not posting a minimal reproducible example. Thank you Igor Tandetnik and Retired Ninja for pointing out the issues I had and helping me out.