Tablice dwuwymiarowe i zagwozdka z jednym char'em

0

(podlinkowuję kontekst sprawy: http://4programmers.net/Forum/Newbie/210976-niepoprawne_dzialanie_funkcji_-_multum_problemow?p=919474#id919474)

Zastosowałem się do rady @rincewind oraz poniekąd do @Shalom i stworzyłem taki oto kod rysujący lub tworzący od podstaw tablicę dwuwymiarową.
Prościej moim zdaniem nie dało się napisać a wszystko jest opatrzone komentarzem. W takim więc razie nie jest to już "spagetti code" (funkcję wyświetlającą odpowiednie napisy i manipulujące funkcją drawcrowd wam oszczędzam bo jest nic nie znacząca).

Problem w tym, że znak zdefiniowany w zmiennej cel nie wyświetla się zawsze, jakby był uzależniony od rand(), chociaż funkcja ta losuje dla niego tylko współrzędne.

// tablica do wypełnienia ludźmi
char tLudzie[wer][kol];
// współrzędne celu
unsigned X, Y;

returned drawcrowd(bool bRysowacNaNowo, bool bUkrycCel, char nic, char cel, char inni, unsigned uLiczebnoscTlumu) {
    // twórz tablicę tLudzie na nowo gdy:
    if (bRysowacNaNowo) {
        // jak rysować na nowo to określ pozycję celu
        X = random(wer, 0);
        Y = random(kol, 0);
        if (X < 0) X = 0;
        else if (X > wer - 1) X = wer - 1;
        if (Y < 0) Y = 0;
        else if (Y > kol - 1) Y = kol - 1;
        // nadpisz tablicę - najpierw wiersz, potem wszystkie kolumny wiersza
        for (int a = 0; a < wer - 1; a++) {
            for (int b = 0; b < kol - 1; b++) {
                nLogic = random(100, 0);
                // bezwarunkowo wstaw znak nicości - można potem nadpisać
                tLudzie[a][b] = nic;
                // ludzie zwykli
                if (nLogic > uLiczebnoscTlumu) tLudzie[a][b] = inni;
                // nadpisz zwykłego "ludzia" jako cel gdy:
                if (a == X && b == Y) {
                        // określ czy masz go wtopić w tłum czy nie
                        switch (bUkrycCel) {
                            case false: tLudzie[a][b] = cel; break;
                            case true: tLudzie[a][b] = inni;
                        }
                }
            }
        }
    }

    // rysuj tłum - wiersz i wszystkie jego kolumny (repeat)
    for (int a = 0; a < wer - 1; a++) {
        for (int b = 0; b < kol - 1; b++) {
            cout << tLudzie[a][b];
        }
        // bezwarunkowo odstęp na końcu kolumn wiersza
        cout << "\n";
    }

    return success;
}

Ktokolwiek wie dlaczego, powiedzmy... X jako char dla zmiennej cel się nie pojawia ZAWSZE, tylko mniej więcej raz na parę uruchomień?

2

Cały czas kod to spaghetti. Zasady:

  • funkcja która ma wiecej niż 20 linijek jest zła i trzeba ją podzielić
  • funkcja która ma wiecej niż 1 poziom zagłębienia jest zła i trzeba ją podzielić
  • funkcja która ma w sobie if..else w 99% przypadków powinna być podzielona na mniejsze funkcje, dla każdego z przypadków
  • funkcja może operować maksymalnie jeden poziom abstrakcji w dół
  • jeśli funkcja wymaga wstawienia komentarza w kodzie to znaczy że fragment który opatrujesz komentarzem powinien byc osobną funkcja o odpowiedniej nazwie
  • funkcja musi (!) realizować zasadę jednej odpowiedzialności -> robić jedną konkretną rzecz. U ciebie funkcja jednocześnie coś tworzy jak i rysuje więc jest zrobiona źle i konieczny jest podział na minimum 2 funkcje
  • nazywanie jakichkolwiek zmiennych w kodzie (wyłączając stąd iteratory pętli) jednoznakowymi nazwami oznacza ze kod jest napisany źle. Ja na przykład nie wiem co sie w tym kodzie dzieje i pojecia nie mam czym jest "x" albo "y"
  • Kody z zasady pisze sie po angielsku a nie po polsku.
    Dobrze napisany kod jest zrozumiały nawet dla osoby która nie ma o nim pojęcia. Uzyskuje sie to za pomocą odpowiednich poziomów abstrakcji.
1

Jaklo przykład jednego z punktów o których mówi @Shalom zamiast:

                tLudzie[a][b] = nic;
                // ludzie zwykli
                if (nLogic > uLiczebnoscTlumu) tLudzie[a][b] = inni;
                // nadpisz zwykłego "ludzia" jako cel gdy:
                if (a == X && b == Y) {
                        // określ czy masz go wtopić w tłum czy nie
                        switch (bUkrycCel) {
                            case false: tLudzie[a][b] = cel; break;
                            case true: tLudzie[a][b] = inni;
                        }

dajesz:

                if ((a==X)&&(b==Y)) tLudzie[a][b]=bUkrycCel?inni:cel;
                else if(nLogic>uLiczebnoscTlumu) tLudzie[a][b]=inni;
                else tLudzie[a][b]`code>A jak jeszcze pozmieniasz:`a => y // małe y może występować razem z dużym Y nie kolidują
b => x
wer => Ysize
kol => Xsize

to natychmiast zauważysz parę błędów.

Masz tu przerobioną całość z poprawionymi błędami pomieszania pionu z poziomem:

unsigned rnd(unsigned up) { return rand()%up; }

void rand_target() { X=rnd(kol); Y=rnd(wer); }

void rand_cell(bool bUkrycCel,char nic,char cel,char inni,unsigned uLiczebnoscTlumu,unsigned y,unsigned x)
  {
   if ((x==X)&&(y==Y)) tLudzie[y][x]=bUkrycCel?inni:cel;
   else if(rnd(100)<uLiczebnoscTlumu) tLudzie[y][x]=inni; // tu zmieniłem na <uLiczebnoscTlumu było >
   else tLudzie[y][x]=nic;
  }

void true_draw() {  for(unsigned y=0;y<wer;++y,cout<<endl) for(unsigned x=0;x<kol;++x) cout<<tLudzie[y][x]; }

void drawcrowd(bool bRysowacNaNowo, bool bUkrycCel, char nic, char cel, char inni, unsigned uLiczebnoscTlumu)
  {
   if(bRysowacNaNowo)
     {
      rand_target();
      for(unsigned y=0;y<wer;++y) for(unsigned x=0;x<kol;++x) rand_cell(bUkrycCel,nic,cel,inni,uLiczebnoscTlumu,y,x);
     }
   true_draw();
  }
0

Aż sam w to nie wierzę, bo reputacja gotowców (choć zbędnych bo sam już próbowałem taki kod zdziałać na podstawie rad @13_th_Dragon) była raczej nienaruszona do tej pory - uwaga! nie działa tak jak powinno! O_O

X znowu pojawia się tylko kilka razy na output... Skasowałem moją wersję i w desperacji wziąłem gotowca ale ten też nie zadziałał! Kurczę, zmieniałem tylko formatowanie...

1

no to pokazuj jak to wywołujesz, pewnie wszędzie masz pomieszane X z Y.

#include <ctime>
#include <cstdlib>
#include <iostream>
using namespace std;

const unsigned wer=20;
const unsigned kol=40;
char tLudzie[wer][kol];
unsigned X,Y;

unsigned rnd(unsigned up) { return rand()%up; }
 
void rand_target() { X=rnd(kol); Y=rnd(wer); }
 
void rand_cell(bool bUkrycCel,char nic,char cel,char inni,unsigned uLiczebnoscTlumu,unsigned y,unsigned x)
  {
   if ((x==X)&&(y==Y)) tLudzie[y][x]=bUkrycCel?inni:cel;
   else if(rnd(100)<uLiczebnoscTlumu) tLudzie[y][x]=inni; // tu zmieniłem na <uLiczebnoscTlumu było >
   else tLudzie[y][x]=nic;
  }
 
void true_draw() {  for(unsigned y=0;y<wer;++y,cout<<endl) for(unsigned x=0;x<kol;++x) cout<<tLudzie[y][x]; }
 
void drawcrowd(bool bRysowacNaNowo, bool bUkrycCel, char nic, char cel, char inni, unsigned uLiczebnoscTlumu)
  {
   if(bRysowacNaNowo)
     {
      rand_target();
      for(unsigned y=0;y<wer;++y) for(unsigned x=0;x<kol;++x) rand_cell(bUkrycCel,nic,cel,inni,uLiczebnoscTlumu,y,x);
     }
   true_draw();
  }
  
int main()
  {
   srand(time(0));
   while(true)
     {
      drawcrowd(true,false,' ','@','*',10);
      cin.sync();
      cin.get();
      for(unsigned i=0;i<10;++i) cout<<endl;
     }
   return 0;
  }

Pojawia się za każdym razem.

EDIT: A może parametr bUkrycCel też losujesz rand'em? Wtedy wszystko się zgadza.

0

bUkrycCel to parametr odgórnie ustalany (dla wypatrywania daję go na true bo X ma być ukryty, ale w testowej wersji WSZĘDZIE miał ustawione false.

Ja ze zmiennymi to raczej jestem ostrożny i nigdy wcześniej nie zdarzały mi się jakiekolwiek koligacje. Tym nie mniej prezentuję cały blok odpowiedzialny za wypatrywanie.

Twoją funkcję *rnd *porzuciłem na rzecz mojej istniejącej już - random(uSkala, nOdejmij) - z parametrów można sobie wywnioskować działanie.

Funkcję aim() na razie zignorujcie proszę, nie jest dokończona ale zrobiona tak że póki co nie wpływa na program szkodliwie.

Zrezygnowałem z parametru uLiczebnoscTlumu na rzecz adjustdiff(...) - returnuje wartość odpowiadającą zdefiniowanej skali trudności gry.

void drawtarget() { X = random(kol, 0); Y = random(wer, 0); }

void pedestrian(bool bUkrycCel, char nic, char cel, char inni, unsigned uLiczebnoscTlumu, unsigned y, unsigned x) {
   if ((x==X) && (y==Y)) tLudzie[y][x] = bUkrycCel?inni:cel;
   else if(random(100, 0) < uLiczebnoscTlumu) tLudzie[y][x] = inni; // tu zmieniłem na <uLiczebnoscTlumu było >
   else tLudzie[y][x] = nic;
}

void showcrowd() { for(unsigned y = 0; y < wer; ++y, cout << endl) for(unsigned x = 0; x < kol; ++x) cout << tLudzie[y][x]; }

void drawcrowd(bool bUkrycCel, char nic, char cel, char inni) {
   drawtarget();
   for (unsigned y = 0; y < wer; ++y) for (unsigned x = 0; x < kol; ++x) pedestrian(bUkrycCel, nic, cel, inni, adjustdiff(70, 60, 50, 35), y, x);
}

// BULLET'S BALLISTICS---------------------
int randomballistic() {
    nLogic = random(100, 0);
    if (nLogic > 85) return 1;
    else if (nLogic < 15) return -1;
    else return 0;
}
int forceballistic(unsigned uSilaWiatru) {
    int vectorForce = 0;
    switch (uSilaWiatru) {
        case 2: ++vectorForce; break;
        case 3: vectorForce += 2;
    }
    return vectorForce;
}
int quarterballistic(quarter qKierunek) {
    int vectorQuarter = 0;
    switch (qKierunek) {
        case west: ++vectorQuarter; break;
        case east: --vectorQuarter;
    }
    return vectorQuarter;
}
int windballistic(quarter qKierunek, unsigned uSilaWiatru) {
    if (quarterballistic(qKierunek) > 0) return quarterballistic(qKierunek) + forceballistic(uSilaWiatru);
    else return quarterballistic(qKierunek) - forceballistic(uSilaWiatru);
}
int gravitationballistic(unsigned uOdleglosc) {
    double G = floor(uOdleglosc / 115);
    return static_cast<int>(G);
}

// WSZYSTKIE RAZEM ODDZIAŁYWUJĄCE NA ZMIENNĄ
int XBullet(unsigned X, unsigned uOdleglosc) {
    int nWynik = X + gravitationballistic(uOdleglosc) + randomballistic();
    return nWynik;
}
int YBullet(unsigned Y, quarter qKierunek, unsigned uSilaWiatru) {
    int nWynik = Y + windballistic(qKierunek, uSilaWiatru) + randomballistic();
    return nWynik;
}

returned checkshot(unsigned Xshot, unsigned Yshot, unsigned X, unsigned Y, unsigned uOdleglosc, quarter qKierunek, unsigned uSilaWiatru) {
    if ((XBullet(Xshot, uOdleglosc) == X) && (YBullet(Yshot, qKierunek, uSilaWiatru) == Y)) return success;
    else return crashed;
}
// ----------------------------------------

returned watching(string strWytyczne) {
    clear();
    cout << "ODSZUKIWANIE Z TLUMU:\n--------------\n\n";

    cout << strWytyczne << "\n";
    pause();

    clear();
    drawcrowd(true, tLegendaOznaczen[0], tLegendaOznaczen[1], tLegendaOznaczen[2]);
    showcrowd();
}

returned aim() {
    cout << "Wiersz --> ";
    cin >> --nLogic;
    cout << "Kolumna --> ";
    cin >> --nLogic2;
    showcrowd();

    return success;
}

returned shot(unsigned Xshot, unsigned Yshot, unsigned uOdleglosc, quarter qKierunek, unsigned uSilaWiatru) {
    bReturned = checkshot(Xshot, Yshot, X, Y, uOdleglosc, qKierunek, uSilaWiatru);

    if (bReturned == success) {
        show(4);
        return success;
    }
    else return crashed;
}

returned weather(string strKierunekWiatru, string strSilaWiatru, unsigned uOdleglosc) {
    wait(2);
    cout << "Kierunek wiatru: " << strKierunekWiatru << "\n";
    wait(2);
    cout << "Wiatr: " << strSilaWiatru << "\n";
    wait(2);
    cout << "Dystans: " << uOdleglosc << " m\n";
    wait(1);
    cout << "\n";

    return success;
}

// kol --> 30; wer --> 6
returned shooting(unsigned uOdleglosc, quarter qKierunek, unsigned uSilaWiatru) {
    drawcrowd(false, tLegendaOznaczen[0], tLegendaOznaczen[1], tLegendaOznaczen[2]);
    nLogic = -1, nLogic2 = -1;
    clear();
    do {
        showcrowd();

        do {
            cout << "\n\nDecyzja (cel/pal) --> ";
            cin >> strKomenda;
        } while (strKomenda == "pal" && nLogic < 0 && nLogic2 < 0);

        if (strKomenda == "cel") aim();
        else if (strKomenda == "pal") bReturned = shot(nLogic, nLogic2, uOdleglosc, qKierunek, uSilaWiatru);
        clear();
        pause();
    } while (strKomenda != "pal");

    if (bReturned == success) return success;
    else return crashed;
}

W mainie wywołuję to tak:

drawcrowd(false, '-', 'X', 'I');

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