2

I'm trying to make a program to print out a grid and given x and y co-ordinates change a value in the grid. For example, if the user entered X:0 and Y:0 it would change the value '9' in the image below to a predefined value (in this case I want to change the value 9 to 0).

enter image description here

My question is, is it possible to update the output of the console so that the '0' would override the '9' without printing out the entire grid again. I want to be able to do this multiple times.

If that is not possible, how can I print out the updated grid the way I have implemented this? If I were to put the display grid for loop in a separate function I would need to call the 2d array as a parameter which I'm sure you cannot do.

Here is what I have:

void generateGrid(int diff){
        srand(time(NULL));
        int arr[maximum][maximum];
            for (int i=0;i<diff;i++)
        {
            for (int j=0;j<diff;j++)
            {
                arr[i][j] = rand() % 9 + 1;
            }
        }
        cout<<"\n\tPuzzle\n\t";
            for(int i=0;i<diff;i++)
            {
                cout<<i<<" ";
            }
                cout<<"\n\n";
            for(int i=0;i<diff;i++)
            {
                cout<<i<<"\t";
                for(int j=0;j<diff;j++)
                {
                    cout<<arr[i][j]<<" ";
                }
                    cout<<"\n";
            }
       int x, y;
        cout<<"\nEnter x value: ";
        cin>>x;
        cout<<"Enter y value: ";
        cin>>y;
        arr[x][y] = 0;
    }

Diff refers to the puzzle size (difficulty)

Elsewhere:

int easy = 5;
int medium = 8;
int hard = 10;
int maximum = 10;
GordanAndrews
  • 77
  • 1
  • 1
  • 8
  • Some consoles have special character sequences that they recognize to, for example, move the cursor to specific positions, or to clear the screen. Search for e.g. *vt100 escape sequences*. – Some programmer dude Mar 15 '17 at 10:53
  • 1
    Also, depending on platform you can use special system functions to do the same. For Windows, [this console function reference](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682073(v=vs.85).aspx) might be handy. On POSIX systems (like Linux or macOS) there aren't such system functions, but if you search for *ncurses* you can find a library which helps you with it. – Some programmer dude Mar 15 '17 at 10:55
  • This is OS specific. Windows for example has SetConsoleCursorPosition() to move the cursor, which then allows you to overwrite in that location – Eyal K. Mar 15 '17 at 11:09
  • Possible duplicate of [How to update a printed message in terminal without reprinting (Linux)](http://stackoverflow.com/questions/1337529/how-to-update-a-printed-message-in-terminal-without-reprinting-linux) – GordanAndrews Mar 16 '17 at 03:43

4 Answers4

4

If your console supports ANSI escape codes, you can go up multiple lines and re-print them, e. g. like this:

printf("hello\n");
printf("\x1b[A");  // you can add the number of lines: "\x1b[7A"
printf("hola \n"); // add sufficient spaces to overwrite previous output!

This works under most linux shells, Windows, however, does not support it until Win10.

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
2

Standard C++ does not support setting individual characters at positions in the console without re-printing. This is OS-specific, and there are comments that address this.

Otherwise, the correct solution is to encapsulate your game board logic into a class. We can use a nested std::vector to handle a dynamically-sized board, and provide functions for getting and setting cells. A separate Print function allows us to print the board to the console as often as we'd like.

class Grid
{
    public:
    Grid(int size) : myGrid(size, std::vector<int>(size, 0)) // initialize grid to be correctly sized and all zeros
    {
       Randomize();
    }

    void Randomize()
    {
        for (size_t i=0;i<myGrid.size();i++)
        {
            for (size_t j=0;j<myGrid[i].size();j++)
            {
                myGrid[i][j] = rand() % 9 + 1;
            }
        }
    }

    void Print(std::ostream& out) const
    {
        out<<"\n\tPuzzle\n\t";
        for(size_t i=0;i<myGrid.size();i++)
        {
           out<<i<<" ";
        }
        out << "\n\n";
        for(size_t i=0;i<myGrid.size();i++)
        {
            out<<i<<"\t";
            for(size_t j=0;j<myGrid[i].size();j++)
            {
                out<<myGrid[i][j]<<" ";
            }
            out<<"\n";
        }
    }

    int GetValue(size_t row, size_t col) const
    {
        // use wraparound for too-large values
        // alternatively you could throw if row and/or col are too large
        return myGrid[row % myGrid.size()][col % myGrid.size()];
    }

    void SetValue(size_t row, size_t col, int val)
    {
        myGrid[row % myGrid.size()][col % myGrid.size()] = val;
    }

    private:
    std::vector<std::vector<int>> myGrid;         
};

Now you can write your main like so:

int main()
{
    srand(time(NULL));
    Grid board(10);
    size_t xValue = 0;
    size_t yValue = 0;

    // game loop. You could even abstract this behavior into another class
    while(true)
    {
        board.Print(std::cout);
        std::cout<<"\nEnter x value: ";
        if (!std::cin) // check for no input
            break;
        std::cin>>xValue;
        if (!std::cin) // check for end of input
           break;
        std::cout<<"Enter y value: ";
        std::cin>>yValue;
        if (!std::cin)
            break;
        board.SetValue(xValue, yValue, 0);

        // other game logic...
    }

    // print board one last time before exit
    std::cout << "Game over. Final board: \n";
    board.Print(std::cout);
}

Live Demo

AndyG
  • 39,700
  • 8
  • 109
  • 143
  • That's a very interesting way to look at it. Are there ways to manipulate the board states and properties? Such as saving a particular board state and restarting that saved state. I'm also curious it it's possible to actually sort the numbers within the puzzle in ascending order per row. – GordanAndrews Mar 16 '17 at 08:21
  • @GordanAndrews yes for sure. It just takes a little learning. For saving, you could write to a file stream. And of course you can sort each sub vector, either manually or with library calls – AndyG Mar 16 '17 at 10:09
0

No, output to the "cout" screen by itself doesn't allow you to change screen contents arbitrarily.

The simplest thing is to redraw the entire gameboard after each move.

To use the terminal as a window, you would have to use a library like "curses", which will understand your terminal (including things like what control codes it uses, and how large it is)

For example, see http://hughm.cs.ukzn.ac.za/~murrellh/os/notes/ncurses.html

Andrew McGuinness
  • 2,092
  • 13
  • 18
0

Just use system("cls");

Then update the 2D array, and reprint it.

Hope it works :).

  • To be noted: Windows specific solution (corresponding linux command is `clear` – on some terminals previous output is just moved out of sight, though, and can still be accessed by scrolling...). – Aconcagua Nov 02 '21 at 16:15