Gra w życie + darwinia + quadlife, błedy w programie

0

Witam, muszę napisać program Gra w życie z dodatkowymi zasadami darwinii (komórka żyje nie dłużej, niż przez określony czas) i quadlife (kolorowanie komórek). Jest to pierwszy tego rozmiaru projekt jaki piszę, i mam niestety kłopoty : /

Problem leży w tym, że kod który napisałem zdaje się nie uśmiercać komórki jeżeli ta ma zbyt dużo/mało komórek - sąsiadów; zabija je jedynie gdy komórka robi się odpowiednio stara (a więc tylko przestrzega zasad darwinii... ). Przeglądałem program już -naście razy, i nadal nie wiem, w czym leży problem. Czy ktoś byłby tak miły, zerknął na kod i mógł mi podpowiedzieć co robię 'źle' i jak to poprawić ?

Piszę w Dev C++ na Win7.

Kod źródłowy

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#define N 12

        struct cell{
           int neighbors;//liczba sąsiadów
           int lifeStatus;//zywa/martwa
           int lifeTime;//wiek
           int color;//kolor
        };

        struct cell komorka[N][N];

//=====PROGRAM=====
int main()
{
   int i, j, rColor, nCounter, stept, next, b, g, r, y;
   
   
   srand(time(NULL));
   (SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x70 ));//białe tło, czarna czcionka
   printf("Nacisnij dowolny przycisk aby zaczac...");
   (SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x07 ));//czane tło, biała czcionka   
   getchar();

//---------------------------------tworzenie świata---------------------------------
   for(i = 0; i <= N; ++i)
   {
        for(j = 0; j <= N; ++j)
        {  
             if(i == 0 || j == 0 || i == N || j == N )//jeżeli komórki są na skraju świata...
             {
                  (komorka[i][j].lifeStatus) = 0;//...nadaj im status martwych...
             }
             else
             {
                  (komorka[i][j].lifeStatus) = (rand()%2);//...w przeciwnym wypadku, losuj status żywe-1/martwe-0
             }
                  
             if( (komorka[i][j].lifeStatus) == 1)//jeżeli komórka zyje...
             {
                 (komorka[i][j].lifeTime) = 1;//...przypisz jej lifeTime == 1
             }
        }
   }
//---------------------------------drukowanie świata po raz pierwszy---------------------------------
   for(i = 0; i <= N; ++i)
   {
        for(j = 0; j <= N; ++j)
        {  
             if(i == 0 || j == 0 || i == N || j == N)//jeżeli komórki są na skraju świata, nic nie rób
             {
                  ;
             }
             else
             {
                  if( (komorka[i][j].lifeStatus) == 0)//jeżeli lifeStatus == 0, to drukuj białe X; komórki są martwe
                  {             
                       (SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x07 )); 
                       printf(" X ");
                  }
                  else//jeżeli lifeStatus == 1, to drukuj O i losuj kolor z czterech:
                  {
                       rColor = (rand()%4);
                       switch(rColor)
                       {
                            case 0:
                                 (SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x01));//niebieski
                                 komorka[i][j].color = 0;
                                 break;
                            case 1:
                                 (SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x02));//zielony
                                 komorka[i][j].color = 1;                  
                                 break;            
                            case 2:
                                 (SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x04));//czerwony
                                 komorka[i][j].color = 2;                  
                                 break;
                            case 3:
                                 (SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x06 ));//żółty
                                 komorka[i][j].color = 3;                  
                                 break;  
                       }
                  printf(" O ");
                 }
             }
        }
        printf("\n                                 \n");
   }
  
   (SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x70 ));//białe tło, czarna czcionka
   stept = 1;   
   printf("\n krok %d", stept);
   (SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x07 ));//czarne tło, biała czcionka

   getchar();
//---------------------------------początek pętli---------------------------------
      //1: zliczyć żywych sąsiadów dla każdej komórki (lifeStatus == 1)
      //2: zapisz aktualną liczbę sąsiadów dla każdej komórki
      //3: jeżeli lifeTime żywej komórki == 50, zabij komórkę
      //4: jeżeli neighbors żywej komórki == 1 lub == 4,5,6,7,8, zabij komórkę
      //5: jeżeli neighbors martwej komórki == 3, ożyw komórkę
      //                 5.1: lifeTime = 1. Ożywiona komórka ma przyjąć kolory większości sąsiadów; jeśli brak większości, nadaj ostatni wolny kolor.
      //6: lifeTime++ dla każdej żywej komórki (naliczanie cykli zycia komórek) 
      //7: czyść ekran i drukuj wyniki

   next = 1;
   while(next > 0)
   {
      
    for(i = 0; i <= N; ++i) //1: zliczyć żywych sąsiadów dla każdej komórki (lifeStatus == 1)
    {
         for(j = 0; j <= N; ++j)
         {
              if(i == 0 || j == 0 || i == N || j == N)//jeżeli komórki są na skraju świata, nic nie rób
              {
                   ;
              }
              else     
              {
              nCounter = 0;//licznik sąsiadów == 0
 
              if(komorka[i-1][j-1].lifeStatus == 1) ++nCounter;//góra-lewo
              if(komorka[i][j-1].lifeStatus == 1) ++nCounter;//lewo
              if(komorka[i+1][j-1].lifeStatus == 1) ++nCounter;//dół-lewo
              if(komorka[i-1][j].lifeStatus == 1) ++nCounter;//góra
              if(komorka[i+1][j].lifeStatus == 1) ++nCounter;//dół
              if(komorka[i-1][j+1].lifeStatus == 1) ++nCounter;//góra-prawo
              if(komorka[i][j+1].lifeStatus == 1) ++nCounter;//prawo
              if(komorka[i+1][j+1].lifeStatus == 1) ++nCounter;//dół-prawo

             (komorka[i][j].neighbors) = nCounter;//2: zapisz aktualną liczbę sąsiadów dla każdej komórki
             }
        }   
   }
//---------------------------------akcje dla komórek zywych---------------------------------
   for(i = 0; i <= N; ++i)
   {
        for(j = 0; j <= N; ++j)
        {
             if(i == 0 || j == 0 || i == N || j == N)//jeżeli komórki są na skraju świata, nic nie rób
             {
                  ;
             }
             else
             {
                  if( (komorka[i][j].lifeStatus) == 1)
                  {
                       //3: jeżeli lifeTime żywej komórki == 50, zabij komórkę                                          
                       if( (komorka[i][j].lifeTime) == 50 )
                       {
                            (komorka[i][j].lifeStatus) = 0;
                       }

                       //4: jeżeli neighbors żywej komórki == 1 lub == 4,5,6,7,8, zabij komórkę                  
                       if( (komorka[i][j].neighbors) == ( 1 || 4 || 5 || 6 || 7 || 8 ) )
                       {
                            (komorka[i][j].lifeStatus) = 0;
                       }
                  }    
             }
        }
   }
//---------------------------------akcje dla komórek martwych---------------------------------
   for(i = 0; i <= N; ++i)
   {
        for(j = 0; j <= N; ++j)
        {
             if(i == 0 || j == 0 || i == N || j == N )//jeżeli komórki są na skraju świata, nic nie rób
             {
                  ;
             }
             else
             {
                  if( (komorka[i][j].lifeStatus) == 0 )
                  {
                       if( (komorka[i][j].neighbors) == 3 )//5: jeżeli neighbors martwej komórki == 3, ożyw komórkę
                       {
                            (komorka[i][j].lifeStatus) = 1;//komórka ożywa
                            (komorka[i][j].lifeTime) = 1;//cykl życia komórki == 1
                          //tutaj będzie nadawanie kolorów żywym komórkom
                       }
                  }
             }
        }
   }
//---------------------------------zwiększanie lifeTime dla żywych komórek---------------------------------
   for(i = 0; i <= N; ++i)//6: lifeTime++ dla każdej żywej komórki (naliczanie cykli zycia komórek)
   {
        for(j = 0; j <= N; ++j)
        {
             if(i == 0 || j == 0 || i == N || j == N )//jeżeli komórki są na skraju świata, nic nie rób
             {
                  ;
             }
             else
             {
                  if(komorka[i][j].lifeStatus == 1)
                  {
                       ++(komorka[i][j].lifeTime);
                  }     
             }
        }     
   }
//---------------------------------czyszczenie ekranu i drukowanie nowego stanu świata---------------------------------
   system("CLS");//7: czyść ekran i drukuj nowe wyniki

   for(i = 0; i <= N; ++i)
   {
        for(j = 0; j <= N; ++j)
        {  
             if(i == 0 || j == 0 || i == N || j == N )//jeżeli komórki są na skraju, nic nie rób
             {
                  ;
             }
             else
             {
                  if( (komorka[i][j].lifeStatus) == 0)//jeżeli lifeStatus == 0, to drukuj białe X
                  {             
                       (SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x07 )); 
                       printf(" X ");
                  }
                  else//jeżeli lifeStatus == 1, to drukuj kolorowe O
                  {
                       //pobierz wartość z (komorka[i][j].color) i wydrukuj wg niej
                       printf(" O ");
                  }
             }
        }
   
        printf("\n                              \n");
   
        }
        
        (SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x70 ));//białe tło, czarna czcionka
        ++stept;
        printf("\n krok %d", stept);
        (SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x07 ));//czarne tło, biała czcionka      

        getchar();
   }
//---------------------------------koniec pętli---------------------------------
   return 0;
}
0

Nie widzę tutaj nigdzie drugiej tablicy pomocniczej. W automacie komórkowym przejście cyklu odbywa się w tej samej chwili dla każdej komórki więc musisz to uwzględnić. Chodzi o to, że gdy np dla jakiejś komórki zliczysz ilość żywych sąsiadów i następnie od razu ją uśmiercisz (czy tam zmienisz jej stan na inny) to dla każdego jej sąsiada nastąpi przekłamanie bo w tym cyklu co wykonujesz sprawdzenie ta komórka jeszcze jest w określonym stanie (np żyje) a ty ją "za wcześnie" uśmierciłeś (czy tam zmieniłeś jej stan na inny). Chyba, że rozwiązałeś to w inny sposób ale nie widzę tego w tym kodzie.

0

Ten kod boli jak "zły dotyk".
Poczytaj co to jest funkcja - i stosuj je.

0

A taki mały szczegół, jeśli:

#define N 12

struct cell komorka[N][N];

To czemu potem robisz:

for(i = 0; i <= N; ++i)
{
   for(j = 0; j <= N; ++j)
   {  
      if(i == 0 || j == 0 || i == N || j == N )//jeżeli komórki są na skraju świata... 

Od 0 do 12 mamy 13 elementów, tablica komórka ma 144 elementy a w programie używasz 169... (daj i<N oraz i==N-1 itd.) Nic Ci się na tym nie wywala?

0

matek3005, nie bardzo łapię o co masz na myśli. Na ile ja to widzę, to nie niszczę komórki zaraz po zliczeniu jej sąsiadów; ja przelatuję przez wszystkie komórki - poza tymi na skrajach tablicy - zliczam ilość ich sąsiadów i zapisuję do 'komorka[i][j].neighbors'. Dopiero po zaktualizowaniu danych dla wszystkich komórek biorę się za podejmowanie akcji; najpierw niszczę te komórki które są za stare ('komorka[i][j].lifeTime' == 50) i później zabijam te które mają "złą" ilość sąsiadów (tj 'komorka[i][j].neighbors' == 1,4,5,6,7,8).

Chodzi mi o to, że najpierw tworzę początkowy świat, a później, na początku pętli sprawdzam stan wszystkich komórek, następnie uaktualniam te informacje (zapisuje stan do komórki), a na koniec podejmuje akcję i drukuje wyniki. Taka była idea programu, kiedy go pisałem.

vpiotr, wiem o tym, i masz zapewne rację. Ale korzystanie z funkcji na moim etapie jest dla mnie trudne i zwyczajnie się w tym gubię a nie mam za bardzo czasu. Plan był taki, ze napisze ten program i jeśli będzie on działał a ja będę mieć czas, to go przerobię by "jakoś wyglądał". Czyli to nie tak, że nie zdaję sobie sprawy, że wygląda jak wyrzucony na plażę bebech...

Kolorowy - czy chodzi ci o to, dlaczego nie używam tych skrajnych elementów tablicy?
Zasadniczo, kiedy korzystałem z pełnej tablicy, komórki dobrze naliczały swoich sąsiadów (konkretnie chodzi o żywych sąsiadów). Problematyczne były jednak komórki położone na skraju tablicy (naliczały błędne wartości), dlatego przyjąłem, że będą one wiecznie martwe i 'ukryte'. Istnieją, ale będąc zawsze martwe nie powodują błędów w naliczaniu sąsiadów.

0

Zmien warunek na:

if ( komorka[i][j].neighbors == 1 || komorka[i][j].neighbors > 3 )

Z tego co patrzyłem to teraz uśmierca prawidłowo.
To o czym pisałem wcześniej dotyczyło notorycznego sprawdzania komórek z poza zakresu. Jeśli i lub j było równe N czyli 12, to sięgałeś do przykładowo:

komorka[12][12]

a maksymalnie powinieneś sięgać do komorka[11][11]

0

Sorry, nie zauważyłem za pierwszym razem sposobu w jaki to rozwiązałeś, w ogóle to ciężko w tym kodzie coś zobaczyć ;p
jak już kolorowy wspomniał, tablice w C/C++ indeksuje się od 0 - N-1 , a nie jak ty to próbujesz robić od 0 - N. Poza tym po co zaciemniasz kod takimi konstrukcjami?

if(i == 0 || j == 0 || i == N || j == N )//jeżeli komórki są na skraju świata, nic nie rób
{
           ;
}

przecież możesz zanegować wyrażenie logiczne :| Poza tym wszystkie warunki i praktycznie każdą linijkę komentujesz. Nie uważasz, że lepiej i szybciej by było pisać kod, który w zasadzie sam siebie komentuje? Czyli nazywać zmienne, funkcje (których niestety nie stosujesz) tak aby tłumaczyły i opisywały swoje przeznaczenie i zastosowanie. W ten sposób zaoszczędziłbyś troszkę czasu i zwiększył przejrzystość kodu i za pewne łatwiej byłoby ci do niego wrócić po jakiejś dłuższej przerwie :]

0

Jeśli chodzi o Darwinię, to polecam odgapić od nich - http://www.introversion.co.uk/darwinia/ :D

0

Kolorowy, program zadziałał w końcu jak należy, komórki umierają i powstają jak powinny, tysiąckrotne dzięki :D Pozostało mi już tylko dodać kolory i przerobić kod na bardziej czytelny.

Dzięki wszystkim za pomoc!

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