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

snake pytanie odnosnie kodu

Ostatnio zmodyfikowano 2017-06-26 14:38
Autor Wiadomość
Chowan
Temat założony przez niniejszego użytkownika
snake pytanie odnosnie kodu
» 2017-06-25 23:40:39
w innym temacie było pytanie odnośnie snake w konsoli, napisałem swojego i chciałby prosić o jakąś konstruktywną krytykę jeśli ktoś będzie miał trochę wolnego czasu.

C/C++
#include <iostream>
#include <windows.h>
#include <conio.h>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <string>
#include <vector>

using namespace std;
const int wysokosc = 20;
const int dlugosc = 40;

struct snake
{
    int px;
    int py;
    int ppx; //poprzednia pozycja X
    int ppy; // poprzednia pozcyja Y
   
} waz;
struct Jablko
{
    int px;
    int py;
} jablko;

void mapa( char tab[ wysokosc ][ dlugosc ] );
void draw( char tab[ wysokosc ][ dlugosc ] );
bool moves( char tab[ wysokosc ][ dlugosc ], char & kierunek, snake & glowa );
bool losuj( char tab[ wysokosc ][ dlugosc ], int & wynik );
void bodymove( char tab[ wysokosc ][ dlugosc ], vector < snake >& cialo, const bool & czyzjedzono );
void save( const int & wynik );
void load();

int main()
{
    while( 1 )
    {
        srand( time( NULL ) );
        int score = 0;
        char klawisz = 'w'; //pocatkowy kierunek ruchu
        waz = { wysokosc / 2, dlugosc / 2 }; //inicjalizacja struktury
        vector < snake > body( 3 );
        char tab[ wysokosc ][ dlugosc ];
        mapa( tab );
        for( int i = 0; i < body.size(); i++ ) // ustawienie ciala weza
        {
            body[ i ].px = waz.px + i + 1;
            body[ i ].py = waz.py;
            tab[ body[ i ].px ][ body[ i ].py ] = 'o';
        }
        jablko = {( rand() %( wysokosc - 2 ) ) + 1,( rand() %( dlugosc - 2 ) ) + 1 }; // inicjalziacja struktury
        tab[ waz.px ][ waz.py ] = 'O'; //ustawienia poczatkowej pozycji weza
        tab[ jablko.px ][ jablko.py ] = '@'; // ustawienie poczatkowej pozycji jablka
        draw( tab );
        while( 1 )
        {
            if( moves( tab, klawisz, waz ) == false ) break;
           
            bodymove( tab, body, losuj( tab, score ) );
            system( "cls" );
            draw( tab );
            score++;
        }
        cout << "GameOver!!!" << " Twoj wynik to: " << score << endl;
        load();
        save( score );
        cout << " ESC aby zakonczyc, inny przycisk aby zaczac od nowa\n";
        if( getch() !=( char ) 27 )
        {
            cout << "Zaczynamy od nowa";
            Sleep( 2000 );
        }
        else break;
       
    }
    return 0;
}
void mapa( char tab[ wysokosc ][ dlugosc ] ) // tworzenie mapy
{
    for( int i = 0; i < wysokosc; i++ )
    {
        for( int j = 0; j < dlugosc; j++ )
        {
            if( i == 0 || i == wysokosc - 1 )
                 tab[ i ][ j ] = '_';
            else if( j == 0 ||( j == dlugosc - 1 ) )
                 tab[ i ][ j ] = '|';
            else tab[ i ][ j ] = ' ';
           
        }
    }
}
void draw( char tab[ wysokosc ][ dlugosc ] ) // rysowanie mapy
{
    for( int i = 0; i < wysokosc; i++ )
    {
        for( int j = 0; j < dlugosc; j++ )
        {
            cout << tab[ i ][ j ];
        }
        cout << endl;
    }
}
bool moves( char tab[ wysokosc ][ dlugosc ], char & kierunek, snake & glowa ) // poruszanie + sprawdzanie czy nie ma kolizji
{
    glowa.ppx = glowa.px;
    glowa.ppy = glowa.py;
    if( kbhit() )
    {
        Sleep( 200 );
        kierunek = getch();
        switch( kierunek ) {
        case 'a':
            waz.py--;
            break;
        case 'w':
            waz.px--;
            break;
        case 's':
            waz.px++;
            break;
        case 'd':
            waz.py++;
            break;
        default:
            waz.px++;
            break;
        }
       
        if(( tab[ waz.px ][ waz.py ] != 'o' ) && !(( waz.px == 0 || waz.px == wysokosc - 1 || waz.py == 0 || waz.py == dlugosc - 1 ) ) )
        {
            tab[ waz.px ][ waz.py ] = 'O'; //tab[waz.ppx][waz.ppy]=' ';
            return true;
        }
        else return false;
       
    }
    else
    {
        Sleep( 200 );
        switch( kierunek )
        {
        case 'a':
            waz.py--;
            break;
        case 'w':
            waz.px--;
            break;
        case 's':
            waz.px++;
            break;
        case 'd':
            waz.py++;
            break;
        default:
            waz.px++;
            break;
        }
       
        if(( tab[ waz.px ][ waz.py ] != 'o' ) && !(( waz.px == 0 || waz.px == wysokosc - 1 || waz.py == 0 || waz.py == dlugosc - 1 ) ) )
        {
            tab[ waz.px ][ waz.py ] = 'O'; //tab[waz.ppx][waz.ppy]=' '; //ustawiam pozycje weze i zeruje poprzednia
            return true;
        }
       
        else return false;
       
    }
}
bool losuj( char tab[ wysokosc ][ dlugosc ], int & wynik ) // tworzenie jablka jesli zostalo zjedzone
{
    if( waz.px == jablko.px && waz.py == jablko.py )
    {
        while( tab[ jablko.px ][ jablko.py ] != ' ' )
        {
            jablko = {(( rand() %( wysokosc - 2 ) ) + 1 ),(( rand() %( dlugosc - 2 ) ) + 1 ) };
        }
        tab[ jablko.px ][ jablko.py ] = '@';
        wynik += 10;
        return 1;
    }
    else return 0;
   
}
void load() //wczytuje najlepszy wynik
{
    ifstream plik;
    plik.open( "snake.txt" );
    if( plik.is_open() )
    {
        string text;
        getline( plik, text );
        cout << text << endl;
        plik.close();
    }
    else if( plik.fail() ) // jesli plik nie istnieje towrzy plik
    {
        cout << "Tworze plik z highscore";
        ofstream plika( "snake.txt" );
        plika << "0";
        plika.close();
    }
}
void save( const int & wynik ) // jesli wynik lepszy od dotychczasowego zapisuje go
{
    fstream plik;
    plik.open( "snake.txt", ios::in | ios::out );
    int a;
    plik >> a;
    while( plik.fail() ) // omija dane do wczytania wyniku
    {
        plik.clear();
        plik.ignore();
        plik >> a;
    }
    plik.close();
    plik.open( "snake.txt", ios::in | ios::out );
    if( wynik > a )
         plik << "Najlepszy wynik do tej pory: " << wynik;
   
    plik.close();
}
void bodymove( char tab[ wysokosc ][ dlugosc ], vector < snake >& cialo, const bool & czyzjedzono ) // poruszanie ciala
{
    cialo[ cialo.size() - 1 ].ppx = cialo[ cialo.size() - 1 ].px; // zapamietanie pozycji ostatniej czesci weza
    cialo[ cialo.size() - 1 ].ppy = cialo[ cialo.size() - 1 ].py;
   
    for( int i = cialo.size() - 1; i > 0; i-- ) // poruszenie ciala
    {
        cialo[ i ].px = cialo[ i - 1 ].px;
        cialo[ i ].py = cialo[ i - 1 ].py;
        tab[ cialo[ i ].px ][ cialo[ i ].py ] = 'o';
    }
    cialo[ 0 ].px = waz.ppx;
    cialo[ 0 ].py = waz.ppy; // ustawieni 1 czesci ciala na miejsce glowy przed ruchem
    tab[ cialo[ 0 ].px ][ cialo[ 0 ].py ] = 'o';
   
    if( czyzjedzono ) // jesli zjedzono jablko waz wydluza sie
    {
        cialo.push_back( { cialo[ cialo.size() - 1 ].ppx, cialo[ cialo.size() - 1 ].ppy } );
        tab[ cialo[ cialo.size() - 1 ].ppx ][ cialo[ cialo.size() - 1 ].ppy ] = 'o';
    }
    else
         tab[ cialo[ cialo.size() - 1 ].ppx ][ cialo[ cialo.size() - 1 ].ppy ] = ' '; // wyzerowanie elemntu na ktorym konczylo sie cialo
   
}
P-162821
latajacaryba
» 2017-06-26 01:45:59
Nazwy zmiennych są nieintuicyjne (bez komentarza nigdy nie wiedziałbym co robi ppx czy ppy). Kiedy IDE podpowiada nazwy, nie ma co bać stosowania długich, np. PoprzedniaPozycjaX
No i dlaczego nazwy raz są po polsku a raz po angielsku?

Poza tym ja bym zrobił coś tego typu, że jak idziesz wężem w dół, to nie możesz nacisnąć "W" (w sensie to nic nie daje). Żeby to wykonać możesz np. sprawdzać kierunek ruchu węża:
C/C++
enum KierunekWeza
{
    gora,
    prawa,
    dol,
    lewa
};

// poruszanie + sprawdzanie czy nie ma kolizji
No właśnie.
Funkcje troche zbyt duze. Może warto zrobić coś takiego:
C/C++
void RuchWeza( Snake & Waz )
{
    IdzPrzedSiebie( Waz );
    if( CzyBylaKolizja( Waz ) == true )
         KoniecGry();
   
}
Rozbij to na mniejsze części. Powinny być jak najmniej zależne od siebie.

No i ostatnia rzecz... to nie jest w tym przypadku jakiś duży błąd, zmienne deklarujemy poza pętlami.


Ale generalnie to fajnie Ci to wyszło :D
P-162822
Chowan
Temat założony przez niniejszego użytkownika
» 2017-06-26 08:14:01
Po pierwsze dzięki za odpowiedź.
Z tymi nazwami to nie wiem czemu tak wyszło :), ale następnym razem od razu zacznę od angielskich.
Nazwy nieintuicyjne, bo pierwsze raz robię coś co wykracza poza 50 linijek i taki jakiś zły nawyk, w funkcjach starałem się dawać w miarę jasne. A te ppx to nie mogłem przez dłuższy czas ustawić sterowania ciałem i siedziałem zdenerwowany i jak w końcu na coś wpadłem to jakoś tak się ustawiło w przypływie euforii.
Co do enum to widziałem coś, ale nie do końca rozumiałem jak to działać by miało, a jak już gdzieś znalazłem to było poruszani zrobione i nie chciałem zepsuć :D. Ustawiłem, że jak wraca na ciało to koniec gry.

Jeśli chodzi o zmienne za pętlami to o te za pierwszym wywołaniem while w int main()? Bo miałem je globalnie ustawione, ale widziałem że to spotka się z delikatna krytyką. Przestawiłem je do maina i ustawiłem pętle, żeby można było zaczynać od początku bez wyłączania gry.

Ogólnie będę zaczynał teraz rozdziały z projektowaniem obiektowym u praty i będę chciał sukcesywnie przenosić to na klasy i funkcje do plików nagłówkowych to postaram się wtedy przepisać to uwzględniając Twoje porady.
P-162824
latajacaryba
» 2017-06-26 12:18:25
C/C++
enum KierunekWeza
{
    Gora,
    Dol,
    Lewa,
    Prawa
}


struct Waz
{
    int MapaPozycjaX
    int MapaPozycjaY;
    Kierunek KierunekRuchu;
    ...
   
}
// I sprawdzasz warunek:

CzyZmienicKierunekRuchu = true;

switch( Waz.KierunekRuchu )
{
case Gora:
    if( klawisz == 's' )
         CzyZmienicKierunekRuchu = false;
   
    break;
   
    // itd.
   
}


A te ppx to nie mogłem przez dłuższy czas ustawić sterowania ciałem i siedziałem zdenerwowany i jak w końcu na coś wpadłem to jakoś tak się ustawiło w przypływie euforii.
https://youtu.be/nXwDEL-ivis

P-162830
pekfos
» 2017-06-26 12:25:03
zmienne deklarujemy poza pętlami.
Bez sprecyzowania - bzdury. Zmienne powinny mieć możliwie mały zakres widoczności, więc jak najbardziej mogą być utworzone w pętli.
P-162831
latajacaryba
» 2017-06-26 12:32:18
@up

To przepraszam, gdzieś kiedyś wyczytałem, że tak być powinno. Zedytuje wypowiedź.
P-162833
Monika90
» 2017-06-26 14:38:42
Zakres widoczności zmiennych powinien być tak mały jak to możliwe, chyba że masz powód by tak nie było. Np. chcesz uniknąć zbędnej dynamicznej alokacji pamięci, więc deklarujesz std::string przed pętlą.
P-162838
« 1 »
  Strona 1 z 1