Dziwny Saper - odkrywanie pól.

0

Witam,

na studiach mam do wykonania projekt z programowania obiektowego - grę saper. Napisałem już część kodu, lecz nie umiem poradzić sobie z odkrywaniem odpowiednich pól po wprowadzeniu koordynat.

Funkcją discover(int a, int b) próbuję przepisywać do tablicy odkrytych pól odpowiednie wartości, ale przepisuje tylko jedną - tą wybraną :/

Kod:

#include <iostream>
#include <ctime>
#include <cstdlib>

using namespace std;
const char BOMB = '*';
const char FLAG = 'f';
const char DISCOVERED = ' ';
const char EMPTY = '0';
const char MAX = '9';

class Board {
public:
    Board();

    Board(int size_x, int size_y) : x(size_x), y(size_y) {
        board = new char **[y];
        for (int i = 0; i < y; i++) {
            board[i] = new char *[x];
        }
        for (int i = 0; i < y; i++) {
            for (int j = 0; j < x; j++) {
                board[i][j] = new char;
                *(board[i][j]) = '0';
            }
        }
        discovered_board = new char **[y];
        for (int i = 0; i < y; i++) {
            discovered_board[i] = new char *[x];
        }
        for (int i = 0; i < y; i++) {
            for (int j = 0; j < x; j++) {
                discovered_board[i][j] = new char;
                *(discovered_board[i][j]) = ' ';
            }
        }
    }

    void display_board() {
        if (x > 10)cout << "   ";
        else cout << "  ";
        for (int i = 0; i < y; i++) {
            if (i < 10) cout << " ";
            cout << " " << i;
        }
        cout << endl;
        for (int j = 0; j < x; j++) {
            cout << " " << j;
            if (j < 10 && x > 10) cout << " ";
            for (int i = 0; i < y; i++) {
                    cout << "  " << *(board[i][j]);
            }
            cout << endl;
        }
    }

    void display_discovered_board() {
        if (x > 10)cout << "   ";
        else cout << "  ";
        for (int i = 0; i < y; i++) {
            if (i < 10) cout << " ";
            cout << " " << i;
        }
        cout << endl;
        for (int j = 0; j < x; j++) {
            cout << " " << j;
            if (j < 10 && x > 10) cout << " ";
            for (int i = 0; i < y; i++) {
                if (*(discovered_board[i][j]) != '*') {
                    cout << "  " << *(discovered_board[i][j]);
                } else cout << "  " << " ";
            }
            cout << endl;
        }
    }

    bool discover(int a, int b) {
        for (int ychange : {-1, 0, 1}) {
            int iy = b + ychange;
            if (iy >= 0 && iy < b)
                for (int xchange : {-1, 0, 1}) {
                    int ix = a + xchange;
                    if (ix >= 0 && ix < a)
                        if (board[iy][ix] != &BOMB && board[iy][ix] < &MAX){
                            discovered_board[ix][iy] = board[ix][iy];
                            discover(ix, iy);
                            return true;
                        }

                }
        }
    }


    void prep_gameboard(int x, int y) {
        board[y][x] = (char *) &BOMB;
    }

    void bomb_counter() {
        for (int i = 0; i < y; i++) {
            for (int j = 0; j < x; j++) {
                if (board[i][j] == &BOMB) {
                    for (int ychange : {-1, 0, 1}) {
                        int iy = i + ychange;
                        if (iy >= 0 && iy < y)
                            for (int xchange : {-1, 0, 1}) {
                                int ix = j + xchange;
                                if (ix >= 0 && ix < x)
                                    if (board[iy][ix] != &BOMB)
                                        (*(board[iy][ix]))++;
                            }
                    }
                }
            }
        }
    }

        friend class Mines;
    private:
        char ***discovered_board;
        char ***board;
        int x, y;
};

class Mines{
public:
    Mines(Board &var, int mines) : mines(mines) {
        int x, y;
        arr_x_pos = new int[mines];
        arr_y_pos = new int[mines];
        for(int i = 0; i < mines; i++){
            do {
                x = rand() % var.x;
                y = rand() % var.y;
            }while(existance(x, y));
            arr_x_pos[i] = x;
            arr_y_pos[i] = y;
        }
    }
    bool existance(int x, int y){
        for(int i = 0; i < mines; i++){
            if(x == arr_x_pos[i] && y == arr_y_pos[i]) return true;
        }
        return false;
    }

    int get_x_pos(int i){
        return arr_x_pos[i];
    }

    int get_y_pos(int i){
        return arr_y_pos[i];
    }

    virtual int mines_amount(int board_size) = 0;

    friend class Board;
private:
    int *arr_x_pos;
    int *arr_y_pos;
    int mines;
};

class LevelEasy : public Mines{
public:
    LevelEasy(Board &var, int board_size) : Mines::Mines(var, mines_amount(board_size)){
    };

    int mines_amount(int board_size) override {
        return (int) board_size * 0.05;
    }
};

class LevelMedium : public Mines{
public:
    LevelMedium(Board &var, int board_size) : Mines::Mines(var, mines_amount(board_size)){
    };
    int mines_amount(int board_size) override {
        return (int) board_size * 0.1;
    }
};

class LevelHard : public Mines{
    public:
    LevelHard(Board &var, int board_size) : Mines::Mines(var, mines_amount(board_size)){
    };
       int mines_amount(int board_size) override {
            return (int) board_size * 0.15;
       }
};

class LevelExtreme : public Mines{
public:
    LevelExtreme(Board &var, int board_size) : Mines::Mines(var, mines_amount(board_size)){
    };
    int mines_amount(int board_size) override {
        return (int) board_size * 0.2;
    }
};


int main() {
    int x, y;

    cout << "Hello! This is simple minesweeper game writen in C++ with classes." << endl;
    cout << "Please type dimensions of your game first horizontal [from 1 to 99], next vertical [from 1 to 99] <Maximal dimensions depends on your screen resolution>" << endl;

    cin >> y >> x;
    while(x < 1 || x > 99 || y < 1 || y > 99){
        cout << "You've given wrong parameters, please, change them" << endl;
        cin >> y >> x;
    }
    cout << "Your minesweeper game will have " << x << " units height and " << y << " units width" << endl;

    Board gameboard(x, y);

    cout << "Now, please type in number of difficulty level you want to play:" << endl << "1.Easy [5% of playground filled with bombs]" << endl << "2.Medium [10% of playground filled with bombs" << endl << "3.Hard [15% of playground filled with bombs]" << endl << "4.Extreme [20% of playground filled with bombs]" << endl;

    int task;

    cin >> task;
    while(task > 4 || task < 1){
        cout << "You picked wrong difficulty level" << endl;
        cin >> task;
    }
    Mines* mines;
    switch(task) {
        case 1:
            mines = new LevelEasy(gameboard, x*y);
            break;
        case 2:
            mines = new LevelMedium(gameboard, x*y);
            break;
        case 3:
            mines = new LevelHard(gameboard, x*y);
            break;
        case 4:
            mines = new LevelExtreme(gameboard, x*y);
            break;
        default:
            cout << "You did not pick any difficulty level" << endl;
            break;
    }

    int diff = mines->mines_amount(x*y);
    cout << "You'll have " << diff << " bombs randomly placed on the playground" << endl;

    for(int i = 0; i < diff; i++){
        gameboard.prep_gameboard(mines->get_x_pos(i), mines->get_y_pos(i));
    }

    gameboard.bomb_counter();

    cout << endl;

    gameboard.display_board();

    cout << endl;
    bool win = true;
    int a, b;
//    do {
        cin >> a >> b;
        gameboard.discover(a,b);
        gameboard.display_discovered_board();
//    }while(win);

    return 0;
}
0

if (iy >= 0 && iy < b) - dlaczego iy < b?

Btw: zamiast ychange możesz napisać delta_y - będzie ładniej :-)

Btw2: nie ma takiego słowa jak existance.

Btw3: amount określa ilość niepoliczalną (np. amount of water) - miny są policzalne, stąd powinieneś wykorzystać number.

Btw4: less is better - wykorzystywanie obiektowości do modelowania różnych poziomów trudności jest takim oop code smell - łatwy, średni i trudny są wariantami tego samego poziomu, dlatego powinieneś mieć raczej coś takiego: Level easy = new Level(0.05); Level medium = new Level(0.1); itd. Nie ma sensu na siłę wpychać wszędzie dziedziczenia.

0

iy < b to błąd, oczywiście, powinno być iy < y i analogicznie niżej z ix.
Btw2. literówka, powinno być existence.
Btw4. Niestety takie są wymogi w zadaniu, a nie bardzo miałem pomysł gdzie więcej wykorzystać dziedziczenie, więc wepchałem to w poziomy trudności.

1 użytkowników online, w tym zalogowanych: 0, gości: 1