0

I have a minesweeper code (not mine), I improved it a bit, but I can't really understand how to properly update the console output so the grid won't print out many times after typing values. This would really optimise the game as well as show the timer in real time. Can someone please explain?

#include<iostream>
#include<time.h>
#include<stdlib.h>
#include<stdio.h>
#include<iomanip>
#include <time.h>

using namespace std;

void reveal(int, int);  
void create_mine_positions();
void cell_number(); 
void create_table(); 
void open_cell(); 
void game();
void print_table(char); 

char table[10][10]; 
char table_mine_positions[10][10]; 
char symbol; 
int flag_counter = 0;
int mines_flagged_counter = 0;
bool end_game_lose = false;
time_t time_since_epoch = time(0);
time_t game_time;

void cell_number(int i, int j)
{
    if (i >= 0 && i < 10 && j >= 0 && j < 10 && table_mine_positions[i][j] != 'X')
        table_mine_positions[i][j]++;
}

void create_mine_positions()
{
    int counter = 0;
    srand(time(NULL));

    for (int i = 0;i < 10;i++)
        for (int j = 0;j < 10;j++)
            table_mine_positions[i][j] = '0';

    int i = 0;
    int j = 0;
    while (counter < 10)
    {
        int i = rand() % 10;
        int j = rand() % 10;
        if (table_mine_positions[i][j] == '0') {
            table_mine_positions[i][j] = 'X';

            cell_number(i - 1, j);
            cell_number(i + 1, j);
            cell_number(i, j - 1);
            cell_number(i, j + 1);
            cell_number(i - 1, j - 1);
            cell_number(i - 1, j + 1);
            cell_number(i + 1, j - 1);
            cell_number(i + 1, j + 1);
            counter++;
        }
    }
}

void create_table()
{
    for (int i = 0;i < 10;i++)
        for (int j = 0;j < 10;j++)
            table[i][j] = '*';
}

void print_table(char arr[10][10])
{
    cout << "    ";
    for (int i = 0;i < 10;i++)
        cout << setw(3) << i;

    cout << endl << "  ";
    for (int i = 0;i < 32;i++)
        cout << "_";
    cout << endl;

    for (int i = 0;i < 10;i++) {
        cout << setw(3) << i << "|";
        for (int j = 0;j < 10;j++)
            cout << setw(3) << arr[i][j];
        cout << endl;
    }
}

void open_cell()
{
    int i, j;

    do
        cin >> i >> j;
    while (i < 0 || i>9 || j < 0 || j>9);

    if (table_mine_positions[i][j] == 'X')
    {
        table[i][j] = 'X';
        end_game_lose = true;

        for (int i = 0;i < 10;i++)
            for (int j = 0;j < 10;j++)
                if (table_mine_positions[i][j] == 'X')
                    table[i][j] = 'X';
    }
    else
        reveal(i, j);
}

void place_or_remove_flag()
{
    int i, j;
    do {
        cin >> i >> j;
        if (cin.fail())
        {
            cin.clear();
            cin.ignore();
        }
    } while (i < 0 || i>9 || j < 0 || j>9);

    if (table[i][j] == '*')
    {
        table[i][j] = 'F';
        flag_counter++;

        if (table_mine_positions[i][j] == 'X')
            mines_flagged_counter++;
    }

    else if (table[i][j] == 'F')
    {
        table[i][j] = '*';
        flag_counter--;
        if (table_mine_positions[i][j] == 'X')
            mines_flagged_counter--;
    }
}

void input_symbol()
{
    cin >> symbol;
    switch (symbol) {
    case 'o': open_cell(); break;
    case 'f': place_or_remove_flag(); break;
    default: input_symbol();
    }
}

void reveal(int i, int j)
{
    if (table[i][j] == '*' && table_mine_positions[i][j] != 'X' && i >= 0 && i < 10 && j >= 0 && j < 10)
    {
        table[i][j] = table_mine_positions[i][j];

        if (table_mine_positions[i][j] == '0')
        {
            reveal(i, j - 1);
            reveal(i, j + 1);
            reveal(i - 1, j - 1);
            reveal(i + 1, j - 1);
            reveal(i + 1, j + 1);
            reveal(i - 1, j + 1);
            reveal(i - 1, j);
            reveal(i + 1, j);
        }
    }
}

bool end_game_win_check()
{
    if (flag_counter == 10 && mines_flagged_counter == 10)
        return 1;
    else
        return 0;
}

void game()
{
    create_table();
    create_mine_positions();

    while (!end_game_lose && !end_game_win_check())
    {
        game_time = time(0);
        print_table(table);
        cout << endl << "Flags:" << flag_counter << endl;
        cout << "Time:" << game_time - time_since_epoch << endl;
        input_symbol();
    }

    if (end_game_lose) {
        print_table(table);
        cout << endl << "GAME OVER" << endl;
    }

    if (end_game_win_check())
        cout << "Time to complete:" << game_time - time_since_epoch << endl;
    cout << endl << "YOU WIN!" << endl;
}

int main()
{
    cout
        << "C O N S O L E - B A S E D   M I N E S W E E P E R"
        << endl << "How to play:"
        << endl << "Enter 'o' , then enter value of i and j to open cell[i][j]."
        << endl << "Enter 'f' ,then enter value of i and j to place "
        << "or remove flag on cell [i][j]."
        << endl << endl;

    game();

    return 0;
}

Also there is a timer under the grid which updates only after removing a tile, it would be great if the console somehow updated constantly so the timer would go even if there wasn't any interaction with the game.

Output:

First comes the name of the game

Then instructions

Then grid

Flags(if used)

and then the timer which is only updated if the values are given.

Biffen
  • 6,249
  • 6
  • 28
  • 36
  • 1
    The game is using blocking input e.g. in `input_symbol()`: `cin >> symbol;`. Based on this, it's hard to make periodical output while it's waiting for input. FYI: [SO: I/O in concurrent program](https://stackoverflow.com/a/48097134/7478597) – Scheff's Cat Apr 16 '21 at 12:09
  • @drescherjm done, it doesn't really show much but I explained the problem above the code. – Anar Mamedov Apr 16 '21 at 12:20
  • @Scheff does that mean that I have to rewrite the whole code? – Anar Mamedov Apr 16 '21 at 12:38
  • If you want a timer part you have to replace the input part – drescherjm Apr 16 '21 at 12:40
  • Well not only the timer part the main problem is the grid that prints every time. – Anar Mamedov Apr 16 '21 at 12:44
  • You can use a library like ncurses or windows api console functions or ansi escape sequences to have it overwrite the grid at the same position. Related: [https://stackoverflow.com/questions/45286/how-can-i-overwrite-the-same-portion-of-the-console-in-a-windows-native-c-cons](https://stackoverflow.com/questions/45286/how-can-i-overwrite-the-same-portion-of-the-console-in-a-windows-native-c-cons) – drescherjm Apr 16 '21 at 12:55
  • Related to ansi escape sequences: [https://stackoverflow.com/questions/16755142/how-to-make-win32-console-recognize-ansi-vt100-escape-sequences](https://stackoverflow.com/questions/16755142/how-to-make-win32-console-recognize-ansi-vt100-escape-sequences) – drescherjm Apr 16 '21 at 12:58

0 Answers0