Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] Programowanie obiektowe - Aplikacja do sterowania robotem

Ostatnio zmodyfikowano 2014-04-05 10:09
Autor Wiadomość
szaroket
Temat założony przez niniejszego użytkownika
[C++] Programowanie obiektowe - Aplikacja do sterowania robotem
» 2014-03-29 19:13:54
Witam. Dostałam za zadanie napisania aplikacji, która umożliwi sterowanie postacią za pomocą wydawanych komend. Ma się poruszać po wczytywanej z pliku planszy. Oprócz tego, że porusza się (góra, dól, prawo, lewo) to ma on za sobą zostawiać ślad w postaci. Dodatkową trudnością jest to, że ma być możliwe łączenie plansz.

Problemem jest, że nigdy nie programowałam w C++, a już zwłaszcza obiektowo (obecnie mija 2 tydzień mojej przygody z C++). Próbowałam sama trochę do tego dojść. Jak na razie wpadłam na to by moimi obiektami była plansza, robot oraz sama gra. Robot miałby metody zmiany kierunku, plansza miałaby metodą dodawania planszy, informowania, czy robot wpadł na ścianę oraz ustawiałaby pozycję początkową robota, a także zapamiętywałą jego instancję. (Ktoś mi mówił by plansza sterowała robotem, ale nie wiem, jak). Do stworzenia tej aplikacji mam nie używać żadnych dodatkowych bibliotek.

Naprawdę bardzo bym prosiła o pomoc. Jakieś podpowiedzi czy nawet małe fragemtny kodów byłyby bardzo pomocne. Próbuję to sama zrobić, ale jakos nie wychodzi, bo np.: nie mam pojęcia jak zczytać z pliku planszę i ustawić w niej robota. Z innymi też mam problem, ale to jakby na razie najpoważniejszy chyba.


P.S.: Kolega dał mi taki kod, bym na jego podstawie zrobiła (jest nieskończony).

C/C++
#include <iostream>
#define STAN_GRA    1
#define STAN_KONIEC 2
#define PUSTE ' '
#define SCIANA '#'
#define WAZ 's'

using namespace std;

class Punkt
{
public:
    Punkt() { x = 0; y = 0; }
    Punkt( int x, int y ) { this->x; this->y = y; }
    int x, y;
};

enum Kierunek { LEWO, PRAWO, GORA, DOL };

class Waz
{
public:
    Waz();
    void zmienKierunek( Kierunek nowy_kierunek );
    void przesunZgodnieZKierunkiem();
   
    Punkt * pobierzElementyWeza() { return elementy_weza; }
    int pobierzDlugoscWeza() { return dlugosc_weza; }
   
    ~Waz();
   
private:
    Kierunek kierunek_weza;
    Punkt * elementy_weza;
    int dlugosc_weza;
};

class Plansza
{
public:
    Plansza();
    Plansza( int wysokosc, int szerokosc );
    Plansza( const Plansza & p );
   
    void rysuj();
    void inicjalizuj( int wysokosc, int szerokosc );
    void umiescWeza( Waz & waz );
    bool czySciana( Punkt p );
   
    ~Plansza();
   
private:
    int wysokosc;
    int szerokosc;
   
    void stworzPole();
    void usunPole();
   
    char ** pola;
};

class Gra
{
public:
    Gra();
    void ruch();
    void inicjalizacja();
    void ustawKierunekWeza( Kierunek k );
    void rysujGre();
    int stan_gry;
   
private:
    Plansza plansza_gry;
    Waz waz;
};

int _tmain( int argc, _TCHAR * argv[] )
{
    Gra gra;
    char akcja = 's';
    gra.rysujGre();
   
    while( akcja != 'q' && gra.stan_gry != STAN_KONIEC )
    {
        cin >> akcja;
       
        switch( akcja )
        {
        case 'r':
            gra.ruch();
            gra.rysujGre();
            break;
        case 'w':
            gra.ustawKierunekWeza( GORA );
            gra.rysujGre();
            break;
        case 'a':
            gra.ustawKierunekWeza( LEWO );
            gra.rysujGre();
            break;
        case 's':
            gra.ustawKierunekWeza( DOL );
            gra.rysujGre();
            break;
        case 'd':
            gra.ustawKierunekWeza( PRAWO );
            gra.rysujGre();
            break;
        case 'q':
            break;
        }
    }
}

Waz::Waz()
{
    dlugosc_weza = 4;
    elementy_weza = new Punkt[ dlugosc_weza ];
   
    elementy_weza[ 0 ].x = 1; elementy_weza[ 0 ].y = 1;
    elementy_weza[ 1 ].x = 1; elementy_weza[ 1 ].y = 2;
    elementy_weza[ 2 ].x = 1; elementy_weza[ 2 ].y = 3;
    elementy_weza[ 3 ].x = 1; elementy_weza[ 3 ].y = 4;
   
    kierunek_weza = DOL;
}

Waz::~Waz()
{
    delete[] elementy_weza;
}

Plansza::Plansza( int wysokosc, int szerekosc )
{
    pola = NULL;
    inicjalizuj( wysokosc, szerokosc );
}

void Plansza::inicjalizuj( int wysokosc, int szerokosc )
{
    this->wysokosc = wysokosc;
    this->szerokosc = szerokosc;
    stworzPole();
   
    for( int x = 0; x < szerokosc; x++ )
    for( int y = 0; y < wysokosc; y++ )
    if( y != 0 && x != 0 && x !=( szerokosc - 1 ) && y !=( wysokosc - 1 ) )
         pola[ y ][ x ] = PUSTE;
    else
         pola[ y ][ x ] = SCIANA;
   
}

void Plansza::stworzPole()
{
    if( pola != NULL ) usunPole();
   
    pola = new char *[ wysokosc ];
    for( int i = 0; i < wysokosc; i++ )
         pola[ i ] = new char[ szerokosc ];
   
}

void Plansza::usunPole()
{
    if( pola != NULL )
    {
        for( int y = 0; y < wysokosc; y++ )
             delete[] pola[ y ];
       
        delete[] pola;
       
        pola = NULL;
    }
}

bool Plansza::czySciana( Punkt p )
{
    if( pola[ p.y ][ p.x ] = SCIANA )
         return true;
    else
         return false;
   
}

void Gra::ruch()
{
    if( stan_gry = STAN_KONIEC ) return;
   
    int dlugosc_weza = waz.pobierzDlugoscWeza();
    Punkt * elementy_weza = waz.pobierzElementyWeza();
   
    waz.przesunZgodnieZKierunkiem();
   
    if( plansza_gry.czySciana( elementy_weza[ dlugosc_weza - 1 ] ) == true )
    {
        cout << "Koniec gry" << endl;
        stan_gry = STAN_KONIEC;
    }
   
    plansza_gry.umiescWeza( waz );
}
P-107425
Monika90
» 2014-03-29 20:32:48
P.S.: Kolega dał mi taki kod, bym na jego podstawie zrobiła (jest nieskończony).
Raczej brzydki kod, ale jest to niemal standardowe C++, wystarczy zmienić nagłówek main z
int _tmain( int argc, _TCHAR * argv[] )
 na
int main( int argc, char * argv[] )


EDIT
która umożliwi sterowanie robotem za pomocą wydawanych komend.
Kto ma wydawać komendy? Użytkownik siedzący przed ekranem? A może mają być czytane z pliku?

ma być możliwe łączenie plansz: np.: uruchamiam planszę 1, ale chcę nadle uruchomić drugą planszę, to one się jakby łączą razem (plansza nr 2 dołącza się do planszy 1 z prawej strony).
Czy zawsze z prawej strony? Czy wysokość wszystkich plansz jest taka sama? Kto wydaje polecenie dodania planszy i kiedy?

ma on za sobą zostawiać ślad w postaci "x"
Czy ślad zostaje na planszy do końca, czy znika po pewnym czasie?
P-107443
szaroket
Temat założony przez niniejszego użytkownika
» 2014-03-29 21:48:14
To jest tak:

Użytkownik przed ekranem wydaje komendy, np.:
użytkownik wpisuje "w" i klika enter - pojawia się nowa plansza z robotem przesuniętym w górę.

Plansze zawsze z prawej strony i są takiej samej wysokości. Poleceni wydaje użytkownik w czasie trwania gry.

Co do śladu - moim zdaniem zostaje do końca, aczkolwiek nie wiem, czy to miał autor polecenia na myśli.

Mam już pewien fragment kodu - na razie mam w nim menu oraz odczytywanie planszy z pliku (aczkolwiek działa to nie tak, jakbym chciała):

http://hostuje.net/file.php?id=e72719485f0b6dab2066ddb83e80ed7c
P-107451
Monika90
» 2014-03-29 22:12:02
Co do śladu - moim zdaniem zostaje do końca, aczkolwiek nie wiem, czy to miał autor polecenia na myśli.
Jak zostaje do końca, to lepiej, bo łatwiej

Początkowa pozycja robota - jak jest określona?
P-107453
szaroket
Temat założony przez niniejszego użytkownika
» 2014-03-29 22:39:00
Nie wiem, jak to w C++ opisać, ale w lewym dolnym rogu planszy.
Ktoś mi napisał, żeby to zrobić za pomocą setPosistion, ale mi wyskakiwał błąd.
P-107455
Monika90
» 2014-03-29 22:52:57
Wczytywanie można zrobić tak, (to jest C++11, więc włącz C++11 w kompilatorze),
C/C++
#include <iostream>
#include <string>
#include <vector>
#include <fstream>

class Board
{
public:
    Board( std::string file_name )
    {
        add_segment( file_name );
       
        //lewy dolny róg
        robot_x_ = 0;
        robot_y_ = rows_.size() - 1;
    }
   
    void add_segment( std::string file_name )
    {
        std::ifstream file( file_name );
        std::string row;
        int y = 0;
        while( std::getline( file, row ) )
        {
            if( rows_.size() <= y )
                 rows_.push_back( std::move( row ) );
            else
                 rows_[ y ] += row;
           
            ++y;
        }
    }
   
    void show() const
    {
        for( int y = 0; y < rows_.size(); ++y )
        {
            auto & row = rows_[ y ];
            if( y == robot_y_ )
            std::cout << row.substr( 0, robot_x_ ) << 'r'
                 << row.substr( robot_x_ + 1, std::string::npos ) << '\n';
            else
                 std::cout << row << '\n';
           
        }
    }
   
private:
    int robot_x_, robot_y_;
    std::vector < std::string > rows_;
};

int main()
{
    Board board( "plansza1.txt" );
    board.show();
    char cmd;
    while( std::cin >> cmd && cmd != 'q' )
    {
        if( cmd == 'p' )
        {
            board.add_segment( "plansza1.txt" );
        }
       
        board.show();
    }
}

zwróć uwagę na zupełny brak sprawdzania błędów, wynik działania:

############
#          #
#          #
#          #
#          #
#          #
#          #
r###########
p
########################
#          ##          #
#          ##          #
#          ##          #
#          ##          #
#          ##          #
#          ##          #
r#######################
p
####################################
#          ##          ##          #
#          ##          ##          #
#          ##          ##          #
#          ##          ##          #
#          ##          ##          #
#          ##          ##          #
r###################################
q
P-107456
szaroket
Temat założony przez niniejszego użytkownika
» 2014-03-29 23:24:33
Czy mogę się dopytać a propos konkretnych pozycji kodu? Chciałabym je zrozumieć, bo to jest dla mnie ważne by nie przepisywać bez zrozumienia. Oczywiście możesz się nie zgodzić - i tak jestem bardzo wdzięczna za pomoc! Co do ruchu robota - postaram się sama to zrobić i ogarnąć by się dało. Mam nadzieję, że niczego nie zniszczę.
I takie dodatkowe pytanie - byłaby możliwość taka, by po dodaniu planszy prawa ściana zanikała? Oraz jeszcze - czy byłoby wstanie umieścić robota w lewym dolnym rogu, ale tak by nie wchodził na ściankę? Próbowałam kombinować z pozycją dla "y", ale nie wyszło.
P-107458
Monika90
» 2014-03-30 00:06:11
czy taki program dałoby się przetworzyć by nie był w C++11?
Da się. Wersja C++98
C/C++
#include <iostream>
#include <string>
#include <vector>
#include <fstream>

const char wall = '#', trace = 'x', robot = 'r';

class Board
{
public:
    Board( const char * file_name )
    {
        add_segment( file_name );
       
        //lewy dolny róg
        robot_x_ = 0;
        robot_y_ = rows_.size() - 1;
    }
   
    void add_segment( const char * file_name )
    {
        std::ifstream file( file_name );
        std::string row;
        int y = 0;
        while( std::getline( file, row ) )
        {
            if( rows_.size() <= y )
                 rows_.push_back( row );
            else
                 rows_[ y ] += row;
           
            ++y;
        }
    }
   
    void show() const
    {
        for( int y = 0; y < rows_.size(); ++y )
        {
            const std::string & row = rows_[ y ];
            if( y == robot_y_ )
            std::cout << row.substr( 0, robot_x_ ) << robot
                 << row.substr( robot_x_ + 1, std::string::npos ) << '\n';
            else
                 std::cout << row << '\n';
           
        }
    }
   
    bool move_robot( int dx, int dy ) //zwraca true wtedy i tylko wtedy gdy ruch był możliwy
    {
        const int new_x = robot_x_ + dx;
        const int new_y = robot_y_ + dy;
        if( new_x >= 0 && new_x < rows_[ 0 ].size()
        && new_y >= 0 && new_y < rows_.size()
        && rows_[ new_y ][ new_x ] != wall )
        {
            rows_[ robot_y_ ][ robot_x_ ] = trace; //zostaw ślad
            robot_x_ = new_x;
            robot_y_ = new_y;
            return true;
        }
       
        return false;
    }
   
private:
    int robot_x_, robot_y_;
    std::vector < std::string > rows_;
};

int main()
{
    Board board( "plansza1.txt" );
    board.show();
    char cmd;
    while( std::cin >> cmd && cmd != 'q' )
    {
        switch( cmd )
        {
        case 'p': board.add_segment( "plansza1.txt" ); break;
        case 'a': board.move_robot( - 1, 0 ); break;
        case 'd': board.move_robot( 1, 0 ); break;
        case 'w': board.move_robot( 0, - 1 ); break;
        case 's': board.move_robot( 0, 1 ); break;
        }
       
        board.show();
    }
}

u mnie działa :)
####################################
xxxxxxxxx  #           #           #
x       x  #           #           #
x  #####x  #   #####   #   #####   #
x  #    x  # r #       #   #       #
x  #    xxxxxx #           #
x  #           #           #
x  #########   #########   #########

I takie dodatkowe pytanie - byłaby możliwość taka, by po dodaniu planszy prawa ściana zanikała?
Tak. W funkcji add_segment ta instrukcja
rows_[ y ] += row;
 dodaje wiersz po prawej stronie, możesz usuwać ostatni znak przed dodaniem (patrz dokumentacja klasy std::string http://en.cppreference.com/w​/cpp/string/basic_string).

czy byłoby wstanie umieścić robota w lewym dolnym rogu, ale tak by nie wchodził na ściankę?
Wymyśl jakiś aglorytm, który znajduje puste pole najbliższe lewemu dolnemu rogowi.
W powyższym programie do pola o współrzędnych x i y, odwołujemy się
rows_[ y ][ x ]
P-107459
« 1 » 2
  Strona 1 z 2 Następna strona