Skocz do zawartości
Pecet256

[C++] busy wait

Rekomendowane odpowiedzi

Wiatm.

Uczę się C++ i potrzebuję tzw. busy wait.

Algorytm ma wyglądać następująco - taki jakby pseudokod:

 

rozpocznij licznie czasu

Jeżeli nie upłynął określony czas{

sprawdź czy dany klawisz nie jest wciśnięty

//tutaj switch lub zestaw ifów dla różnych klawiszy i goto do wyskoczenia z pętli

zaktualizuj liczenie czasu.

}

gdy czas upłynął wykonaj domyślną opcję i kontynuj program dalej.

 

Niestety pętla oczekująca z ctime okazuje się tutaj bezużyteczna ( nie można nic wstawić do pętli bo szaleje).

Zastosowanie sleep też nie działa (zobacz poniżej)

	//niedziala.cpp
	#include <iostream>
#include <unistd.h>
#include <conio.h>
int main()
{
    using namespace std;
    int licznik =0;
    while(licznik < 100){
        sleep (10);
        if (getch () == 27){
            goto koncowka;
        }
        licznik=licznik+1;
        cout << licznik;
    }
    koncowka:
    return 0;
}
	

kompilator codeblocks

 

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dlaczego stosujesz "goto"?

Opisz dokładniej co nie działa lub zachowuje się niezgodnie z założeniami. Określenie "szaleje" kompletnie nic nie mówi.
Napisz jaki jest ten czas oczekiwania na wciśnięcie klawisza i co chcesz osiągnąć stosując funkcję sleep.

Chyba mniej więcej widzę co tu masz nie tak (wszystko ;) ) ale dobrze jakbyś potrafił szukać błędów (składniowych i algorytmicznych), bo to część nauki języka i programowania. Zestawienie założeń z tym jak program się zachowuje i co zwraca jest podstawą szukania błędów. O ile algorytm przedstawiłeś, tak z opisem działania jest duży problem. Czasem nawet samo wyartykułowanie co dzieje się nie tak potrafi naprowadzić na błąd.
Nie musi to być naukowy opis, byle był zrozumiały, były podstawy do dalszej diagnozy lub podpowiedzi co może być nie tak. Na razie to wygląda jakbyś poszedł do lekarza i powiedział "boli mnie", ale gdzie, jak, w jakich okolicznościach nie określasz? ;)

Edytowane przez Bono[UG]

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Co do tego "szaleje" to chyba się pomyliłem, bo wstawiłem w pętli podbijanie licznika i wypisywanie go na konsolę i zawaliło cały ekran cyframi... Ale to dlatego, że w sekundzie jest duże jednostek czsu (TICS_PER_SEC). Może to była pętla "nieskończona" - jutro sprawdzę.

Kod który wkleiłem na forum daje czarną konsolę i nie wyświetla licznika.

Ogólnie to chcę zrobić grę w "węża" - tzw. "snake" w konsoli (ASCI-art).

Będzie pętla i zmienna opisująca kierunek ruchu węża. Gdy użytkownik naciśnie klawisz wywołana zostanie określona akcja - strałki zmiana zmiennej opisującej kierunek ruchu węża i wyjście z pętli opóźnienia, -esc wyjście z programu. Gdy upłynie czas to nie jest zmieniany kierunek ruchu.

Samo przesunięcię węża to będzie funkcja wstawiona ZA pętlą busy wait. - Pierw kopiowanie tablicy struktur węża, a następnie przesunięcie głowy i zmiana lokalizacji elementów ogona - tj. element o indeksie 1 otrymuje lokalizaje głowy, element o indeksie 2 otrzymuje lokalizację elementu o indeksie 1 itd. aż do końca ogona. Gdy w poprzedniej iteracji pętli wąż zjadł pokarm to dodawany jest kolejny segment o starej lokalizacji ostatniego segmentu. Mówiąc lokalizajca mam na myśli współrzędne (zobacz opis węża poniżej).

Waż to tablica struktur. Bardzo prostych, w każdej strukturze są 2 zmienne int - lokalizacja segmentu w pionie i w poziomie. Element o indeksie 0 w tablicy to głowa, pozostałe to segmenty ogona. Identycznie prezentuje się struktura opisująca pokarm węża.

Goto można tutaj chyba zastąpić zestawem switch - break (?)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach
18 godzin temu, Pecet256 napisał:

Kod który wkleiłem na forum daje czarną konsolę i nie wyświetla licznika.

Bo stoi na "getch()", czeka na wciśniecie klawisza.

18 godzin temu, Pecet256 napisał:

Goto można tutaj chyba zastąpić zestawem switch - break (?)

goto i switch to dwie różne sprawy.
Jeżeli chcesz przerwać pętlę przy pomocy "break", to nie można użyć switcha, trzeba pobawić się w konstrukcję "if else". Do doczytania sterowanie pętlami (continue, break itp.).
Jest jeszcze kwestia co chcesz przerwać, gdzie wyskoczyć. Jak zakończyć program, to można użyć "exit". Do sprawdzenia, czy wszystkie destruktory zadziałają, pozwalnia się pamięć (na co dzień robię pod linuksem i tam system sprząta po ubiciu procesu, nie wiem jak windowsy to obsługują). Jeżeli wychodzisz z funkcji, to "return". Można też kombinować z dodatkowymi warunkami w pętli i przestawiać flagę. Dużo zależy od konstrukcji programu.

goto jest momentami wygodne ale przy większych projektach utrudnia prześledzenie programu, masz skok w nie do końca sprecyzowane miejsce. Nie wiem też jak się zachowa jak z funkcji działającej na wątku wyskoczy się gdzieś poza nią. Takich konstrukcji się zazwyczaj unika.

 

Przechodząc do sedna problemu.
Oczywiście rozwiązań jest wiele ale generalnie konstrukcję takiej pętli poprawnie zdefiniowałeś w pseudokodzie (poza goto ;) ). Inne pytanie jak się to wpisze w całą grę. To już kwestia jak chcesz sterować akcjami, czy naciśnięcie klawisza wymusza ruch, czy czekasz do końca ustalonego interwału/ticku gry. Na pewno wygodniej będzie zamknąć tą pętlę w funkcji, gdzie argumentem będzie np. czas/licznik opóźnienia, a zwraca kierunek ruchu/akcję/symbol klawisza (dobrze by było odfiltrować nieużywane). Łatwiej będzie przerwać pętlę, obsłużyć klawiaturę.

Do poprawy w kodzie użycie metod nie blokujących czytania wciśniętych klawiszy. Nie wiem czy są jakieś, które kompleksowo to załatwiają (np. kod znaku jak był wciśnięty, -1 przy braku), czy będziesz musiał rozbić to na dwie operacje: spr. czy wciśnięty, odczytanie.
Trochę pogrzebałem i znalazłem "kbhit()" do sprawdzenia czy coś jest w buforze klawiatury. Pseudokodowo będzie to konstrukcja: if wciśnięty_klawisz then czytaj_klawisz.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

========

long post

========

No cóż...

5 godzin temu, Bono[UG] napisał:

Bo stoi na "getch()", czeka na wciśniecie klawisza.

No właśnie mi chodzi o sposób taki, żeby nie czekało, tylko żeby przy każdej iteracji pętli opóźniającej sprawdzało, czy nie jest naciśnięty klawisz, i jeżeli jest naciśnięta któraś ze strzałek lub ESC to wtedy ma wychodzić z pętli opóźniającej i zmieniać zmienną sterującą / wychodzić z gry.

Opisze algorytm (samej gry, bez menu, etc) jeszcze raz, w inny sposób.

====================================

Początek pętli gry {

Zaktualizuj i  wyświetl planszę

Zacznij liczyć czas

Rozpocznij pętlę oczekującą{

Sprawdź czy nie jest naciśnięty klawisz

Jeżeli jest naciśnięty ESC to wyjdź z gry

Jeżeli jest naciśnięta strzałka to zmień zmienną sterującą wężem ORAZ wyjdź z pętli opóźniacjącej <- tutaj może być goto

zaktualizuj liczenie czasu

zakończ pętlę oczekującą}

Wywołaj funkcję przesunięcia węża (argumenty - tablica struktur segmentów węża, długość węża, plansza jako tablica liczb char, zmienna sterująca wężem, licznik punktów)[

Sprawdź jake jest pole na które zostanie przesunięta głowa

Przekopiuj współrzędne segmentów węża do tablicy tymczasowej

Jeżeli pole do przesunięcia głowy jest ścianą LUB innym segmentem węża to wyjdź z gry i wyświetl plansze "KONIEC GRY" z wynikiem

Jeżeli pole do przesunięcia głowy jest puste to przesuń tam głowę, przesuń segment 1 na poz. głowy, segment 2 na poz. segmentu 1, etc do końca węża, zwiększ licznik punktów

Jeżeli pole do przesunięcia głowy jest polem z pokarmem to przesuń tam głowę, przesuń segment 1 na poz. głowy, segment 2 na poz. segmentu 1, etc do końca węża ORAZ dodaj nowy segment o starej pozycji ostatniego segmentu i zwiększ zmienną określającą długość węża o  i zwiększ licznik punktów}

]

W tej funkcji do przesuwania węża to chyba argumenty będą musiały być wskaźnikami, aby operować na tych samych zmiennych a nie tworzyć lokalne, no chyba, że zrobię zmienne statyczne poza mainem dla całego programu.

Jabyś nie rozumiał, to mogę to napisać w pseudokodzi a'la stare BAISCi czyli onumerować wszystko i zrobić przejścia do konkretnych numerów (to nieszczęsne goto). To co jest w kańciastych nawiasach to opis funkcji przesuwającej węża.

 

PS. W jednej z książek Praty to jest taki cytat, że goto to "Pole nieograniczonych nadużyć", a w innej autor napisał, że uchodzi powszechnie za brzydkie i brudne rozwiązanie.

A co do switch, to jak tam są różne warunki (case) to jak np. są 4 i pozycja aktywna przejdzie do 2 to wykona także 3, 4 (?) i chyba można tam wsadzić break.

Co do obiektowości, jeszcze do niej nie doszedłem, ale wiem, że możliwości ma super.

[Mam cichą nadzieję, że forum się nie "rozjedzie" tak długim postem]

[EDIT] W tych samych podręcznikach jest mowa, że goto może zostać wykorzystane do wychodzenia z bardzo głęboko zakorzenionych pętli.

 

Edytowane przez Pecet256
dopisanie o goto w wychodzeniu z pętli bez double post

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

@up pisałem o tym ;)

Chcesz sterować strzałkami, zdajesz sobie sprawę, że są reprezentowane przez dwa znaki?

Z tego opisu wygląda, że im szybciej będzie się wciskać klawisze, tym szybciej gra będzie chodziła. Czy to zamierzony efekt?
Nie jest to ani dobre ani złe, po prostu taka będzie właściwość gry.

Struktura trzymania węża.
Zastanów się jak ta struktura ma wyglądać. Pierwsza rzecz, to jak jest reprezentowany segment, druga w jakiej strukturze trzymać segmenty. Mi się tutaj narzuca lista współrzędnych i najlepiej bez zabawy w ręczną konstrukcję, czyli użycie kontenera "list". http://www.cplusplus.com/reference/list/list/
Nie wiem po co chcesz kopiować węża do tymczasowej tablicy. Nic to nie da do wydajności, bo tak czy inaczej czy przy przepisywaniu do tablicy, czy sprawdzaniu kolizji musisz przeiterować się po liście segmentów.
Kolejna sprawa, to po co przesuwać segmenty węża? To masa niepotrzebnych operacji. Wystarczy manipulować głową i ogonem:
- przy zwykłym ruchu dopisać na początek listy nową pozycję głowy i usunąć ostatni element listy
- przy zjedzeniu i wydłużeniu, wystarczy dopisać nową pozycję głowy (+/- jak bardzo chcesz skomplikować wydłużanie węża)

Tak, trzeba przekazywać wskaźnik lub referencję. W funkcji musi być możliwość trwałej manipulacji.
W zmienne globalne lepiej się nie bawić. W statyczne też nie, one przydają się do innych rzeczy (np. wartość współdzielona między wieloma obiektami tej samej klasy, licznik wywołania funkcji, flaga pierwszego wywołania).

goto
Popatrz na sugestię z funkcją od obsługi oczekiwania na klawisz. Jeżeli zamkniesz ten fragment kodu w funkcji, to wyjście z pętli zrobisz returnem np. zwracając kod klawisza lub kod operacji. Niech kod wywołujący funkcję martwi się co dalej z tym fantem zrobić (wykonać ruch, zakończyć grę itp.), tutaj robisz tylko obsługę czekania na reakcję gracza.

Jeżeli w kodzie są tak głęboko zagrzebane pętle, że jedynym sposobem jest goto, to jest kiepsko napisany.

 

switch
Wewnątrz break przerywa switcha, nie ma możliwości sterowania konstrukcją na zewnątrz. Tak samo jeżeli jest kilka pętli, to break/continue dotyczy tej na której poziomie polecenie zostanie wykonane. Do doczytania.
Na przykładzie chyba najprościej:

switch(test)
{
  case 1: print "1"
  break;
    
  case 2: print "2"
  break;
    
  case 3:
  case 4: print "34"
    
  default:
    print "dd"
}

Jeżeli dobrze pamiętam to:
- w przypadki 1 wypisze "1" i przerwie dalsze działanie switcha
- tak samo w przypadku 2
- zarówno dla 3 jak i 4 wypisze "34"
- przy braku właściwej wartości wypisze "dd" ale przy 3 i 4 też wypisze

Switch sprawdza czy wartość na wejściu zgadza się z kolejnymi wartościami, jeżeli tak to wykonuje kod w danym case. Jeżeli natrafi w nim na break, to przerywa dalsze sprawdzanie, jeżeli nie ma przerwania, to sprawdza kolejne casy i na końcu wykonuje domyślną akcję.

break przerwie tylko wykonywanie switcha, więc nie da się w tym miejscu przerwać pętli opinającej switch.

Edytowane przez Bono[UG]

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach
W dniu 20.09.2020 o 12:11, Bono[UG] napisał:

Z tego opisu wygląda, że im szybciej będzie się wciskać klawisze, tym szybciej gra będzie chodziła. Czy to zamierzony efekt?
Nie jest to ani dobre ani złe, po prostu taka będzie właściwość gry.

Tak, właśnie chcę taką właściwość.

Co do struktury węża jest to zrobione tak:

	//Przed mainem
	//Deklaracja struktury segmentu weza;
struct segment
{
    int poz_wiersz;
    int poz_kolumna;
};
//Deklaracja struktury pokarmu do zebrania;
struct pokarm
{
    int poz_wiersz;
    int poz_kolumna;
};
	 
	======================================
	 
	//Już w maine
	//waz jako tablica - rownanie wylicza makszymlna dlugosc weza;
    // segment o numerze 0 - glowa, pozostale - segmenty ogona;
    segment snake [(wiersze-2)*(kolumny-2)];
	

 

Równanie wylicza maksymalną długość węża - zobacz.

	//Stale - wielkosc planszy
    const int wiersze = 20;
    const int kolumny = 90;
	

Po tym kodzie znaki w tablicy char plansza [wiersze][kolumny]; w pętli ustawiane są na spacje a potem pierszy i ostatni wiersz oraz pierwsza i ostatnia kolumna są ustawiane na X jako ściany.

 

[edit]

Właśnie chcę funkcję, która sprawdzi czy w danym momencie naciśnięty jest klawisz, i jeżeli tak, to zwróci jego numer identyfikacyjny. Jeżeli nie strzałki, to może WASD.

I jescze jedna, która opróżni bufor klawiszy.

PS. A tzw. wirtualne kody klawiszy ?

Jeszcze raz o wężu. Wiem, że nie jest to najefektywniejsza metoda, ale łatwo ją zaprogramować, wystarczy pętla. Co jest w tej metodzie reprezentowania węża złego?

Edytowane przez Pecet256

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Jak sprawdzasz w tej tablicy, czy to już koniec węża?
Mi do reprezentacji węża narzuca się lista, bo nie trzeba się bawić w ciągłe przerzucanie zawartości tablicy. W liście wystarczy dopisywać element z przodu i kasować z tyłu, dwie operacje zamiast tyle ile wąż mierzy.

Deklarujesz dwie identyczne struktury o różnych nazwach, zamierzasz je w przyszłości o coś rozbudować, czy mają służyć wyłącznie do reprezentacji położenia?
W drugim przypadku, to osobiście dałbym jedną strukturę np. "pozycja", a potem deklarował zmienne "pozycja pokarm;", "list<pozycja> waz;" itp.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Zapomniałem napisać w dzisiejszym poście, że długość węża określa zmienna w maine.

Tak, wiem, że struktura określająca położenie pokarmu także mogłaby być typu segment.

V

V

V

Moim największym probleme jest obecnie jednak ta nieszczęsn funkcja zwracająca naciśnięty klawisz. kbhit()  chyba się nie nadaje, bo mi nie działa. Funkcja nie ma czekać na naciśnięcie, ale ma sprawdzić, czy w danym momencie jest naciśnięty klawisz/klawszie i wydać jaki/jakie - w tym przypadku wystarczy 1 klawisz. Być może okaże się konieczna też funkcja czyszcząca bufor klawiszy. (Czy cin.clear się nada?)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Pokaż jak ta funkcja teraz wygląda.

3 godziny temu, Pecet256 napisał:

długość węża określa zmienna w maine

Według mnie słabe rozwiązanie.

Edytowane przez Bono[UG]

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Funkcji oczekiwania i sprawdzania czy jakiś klawisz jest naciśnięty jeszcze nie mam.

Za to zrobiłem funkcję "testową" wypisującą współrzędne segmentów węża oraz funkcję przesuwania węża.

Funkcja testowa:

	void pokazweza(segment snake [(wiersze-2)*(kolumny-2)],int dlugosc){
    int licznik=0;
    while(licznik<dlugosc){
        cout << "==========================================="<<endl;
        if(licznik==0){
            cout <<"GLOWA"<<endl;
        }
        else{
            cout << "SEGMENT no. " << licznik<<endl;
        }
        cout << "-------------------------------------------"<<endl;
        cout << "wartosc zmiennej poz_wiersz = " << snake[licznik].poz_wiersz<<endl;
        cout << "wartosc zmiennej poz_kolumna = " << snake[licznik].poz_kolumna<<endl;
	        licznik=licznik+1;
    }
	}
	

Funkcja przesuwająca:

	int przesunweza(segment snake [(wiersze-2)*(kolumny-2)],int * dlugosc,char plansza[wiersze][kolumny],kierunki wektor, int * punkty){
    int licznik;
    segment tymczasowa [*dlugosc+2];
    while(licznik<*dlugosc){//Kopiuje weza do tablicy tymczasowej
        tymczasowa[licznik].poz_kolumna=snake[licznik].poz_kolumna;
        tymczasowa[licznik].poz_wiersz=snake[licznik].poz_wiersz;
        licznik=licznik+1;
    }
    enum wyjscia{
    puste_pole=0,
    pokarm=1,
    sciana=2,//lub ogon
    };
    wyjscia wartosc;
    switch(wektor){
        case gora:
            snake[0].poz_wiersz=snake[0].poz_wiersz-1;
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]=='X'){
                wartosc=sciana;
                break;
            }
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]=='O'){
                wartosc=sciana;
                break;
            }
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]=='p'){
                wartosc=pokarm;
            }
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]==' '){
                wartosc=puste_pole;
            }
            break;
        case lewo:
            snake[0].poz_kolumna=snake[0].poz_kolumna-1;
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]=='X'){
                wartosc=sciana;
                break;
            }
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]=='O'){
                wartosc=sciana;
                break;
            }
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]=='p'){
                wartosc=pokarm;
            }
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]==' '){
                wartosc=puste_pole;
            }
            break;
        case dol:
            snake[0].poz_wiersz=snake[0].poz_wiersz+1;
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]=='X'){
                wartosc=sciana;
                break;
            }
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]=='O'){
                wartosc=sciana;
                break;
            }
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]=='p'){
                wartosc=pokarm;
            }
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]==' '){
                wartosc=puste_pole;
            }
            break;
        case prawo:
            snake[0].poz_kolumna=snake[0].poz_kolumna+1;
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]=='X'){
                wartosc=sciana;
                break;
            }
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]=='O'){
                wartosc=sciana;
                break;
            }
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]=='p'){
                wartosc=pokarm;
            }
            if (plansza[snake[0].poz_wiersz][snake[0].poz_kolumna]==' '){
                wartosc=puste_pole;
            }
            break;
            }
	            if (wartosc==2){//Zwraca 2 gdy glowa weza uderza o sciane lub o ogon
                return 1;
            }
            licznik=1;
            while(licznik<*dlugosc){
                snake[licznik]=tymczasowa[licznik-1];
                licznik=licznik+1;
            }
            if(wartosc==1){
                snake[*dlugosc]=tymczasowa[*dlugosc-1];
                *dlugosc=*dlugosc+1;
                *punkty=*punkty+1;
            }
            return 0;
	}

PS: W nagłówki (przed mainem i prototypami funkcji) mam taki enumerator:

	//Enumerator - kierunki
enum kierunki{
    gora=0,
    lewo=1,
    dol=2,
    prawo=3
};

Jakbyś chciał, to mogę wstawić na forum całą obecną treść pliku - uwaga nie ma jeszcze nawet głównej pętli gry, ale może chciałbyś zobaczyć jak zrobiona jest tablica - plansza?

Co sądzisz o moich funkcjach?

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Jak nie masz jeszcze tej funkcji, to ciężko podpowiadać. Myślałem, że dla testów przerobiłeś to co było na samym początku.

Pierwsza uwaga, to spróbuj na forum przy wstawianiu kodu wybrać język C, powinno wtedy pokolorować składnię i będzie się łatwiej czytało.

A odnośnie samych funkcji, to pierwsze co mi się rzuca w oczy to pętle. Czemu "while" a nie "for" skoro znasz długość i zawsze zwiększasz licznik?

Druga rzecz, to w funkcji przesuwającej w switchu masz 4x ten sam kod, warto coś z tym zrobić, żeby było czytelniej i przede wszystkim nie powtarzać się niepotrzebnie. Można to zamknąć w funkcji lub podejść inaczej do sprawdzenia zawartości pola.
Powiązana sprawa, to po co na starcie przepisywać węża do tymczasowej tablicy? Jeżeli będzie przegrana, to szkoda marnować zasoby na zbędną operację. Osobiście najpierw bym sprawdził co dany ruch spowoduje, a potem brał się za aktualizację węża.

Można do tego podejść np. tak:
- zapamiętujesz pozycję głowy w tymczasowych zmiennych (np. int x,y;) lub zmiennej typu segment (chyba nawet lepiej)
- sprawdzasz jaki jest kierunek ruchu i według niego zmieniasz pozycję w tych tymczasowych zmiennych/zmiennej
- sprawdzasz co na planszy się znajduje pod tą nową pozycją i zapamiętujesz skutek
- wykonujesz akcję przesunięcia węża lub wyjścia z gry

Jeżeli chodzi o przesunięcie, to przy opóźnieniu tej operacji, tak jak proponuję, nie potrzeba tymczasowej tablicy, można operację przeprowadzić na samym wężu. Wystarczy przepisywać od ogona, w zależności czy zjadł, czy nie będzie trzeba dobrać indeksy początkowe. Na koniec w [0][0] wpisujesz pozycję ze zmiennej tymczasowej.
Przepisanie odbędzie się raz zamiast dwa razy i tylko wtedy kiedy nie ma przegranej.

Jeszcze jedna uwaga o przepisywaniu tablicy.
Niepotrzebnie zagłębiasz się w zawartość segmentu. Manipulujesz na elementach tablicy przesuwając je, nie trzeba wiedzieć co mają w środku.

segment tablica[rozmiar];

tablica[1]=tablica[0]; //proste przepisanie pierwszego elementu tablicy na kolejną pozycję

Przy bardziej rozbudowanych strukturach zajedziesz się z leceniem po wszystkich elementach. Oczywiście trzeba mieć z tyłu głowy, że czasem mogą być problemy z prostym przepisaniem, kiedy struktura jest skomplikowana ale wtedy można zdefiniować/przeciążyć operator przypisania "=" lub funkcję przepisującą i mieć to napisane raz, a nie za każdym razem jak trzeba operować na całej strukturze.
Po to są struktury, a w dalszej kolejności obiekty, żeby dało się operować na nich jako całości. Tutaj stosujesz tablicę segmentów identycznie jakby to była tablica dwuwymiarowa, nie masz żadnego zysku z zastosowania struktury.
Zresztą robisz tak na końcu jak z tymczasowej przepisujesz do węża.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

 

Zmodyfikowałem trochę funkcje przesuwającą węża.

int przesunweza(segment snake [(wiersze-2)*(kolumny-2)],int * dlugosc,char plansza[wiersze][kolumny],kierunki wektor, int * punkty){
    int licznik;
    segment glowa;//Przechowuje wspozedne glowy weza
    glowa=snake[0];

    enum wyjscia{
    puste_pole=0,
    pokarm=1,
    sciana=2,//lub ogon
    };
    wyjscia wartosc;

    switch(wektor){
        case gora:
            glowa.poz_wiersz=glowa.poz_wiersz-1;
            break;
        case lewo:
            glowa.poz_kolumna=glowa.poz_kolumna-1;
            break;
        case dol:
            glowa.poz_wiersz=glowa.poz_wiersz+1;
            break;
        case prawo:
            glowa.poz_kolumna=glowa.poz_kolumna+1;
            break;
            }


    //Sprawdzanie na jakie pole jest przesuwana glowa weza
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]=='X'){
        wartosc=sciana;
        }else
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]=='O'){
        wartosc=sciana;
        }else
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]=='p'){
        wartosc=pokarm;
        }else
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]==' '){
        wartosc=puste_pole;
        }

    if(wartosc!=2){
        segment tymczasowa [*dlugosc+2];
        licznik=0;
        while(licznik<*dlugosc){//Kopiuje weza do tablicy tymczasowej
            tymczasowa[licznik]=snake[licznik];

            licznik=licznik+1;
        }
        snake[0]=glowa;
        licznik=1;
        while(licznik<*dlugosc){
            snake[licznik]=tymczasowa[licznik-1];
            licznik=licznik+1;
        }
        if(wartosc==1){
            snake[*dlugosc]=tymczasowa[*dlugosc-1];
            *dlugosc=*dlugosc+1;
            *punkty=*punkty+1;
        }
    }

    if (wartosc==2){//Zwraca 2 gdy glowa weza uderza o sciane lub o ogon
        return 1;
    }
    return 0;

}

 

Oprócz tego zastanawiam się, nad użyciem do sterowania czegoś takiego - na razie mam szkielet - potrzebuję funkji sprawdzającej czy jest naciśnięty klawisz:

Ma to wyglądać mniej więcej tak:

using namespace std;
    float secs;
    int kod_klawisza;
    secs=czas oczekiwania;
    clock_t delay = secs * CLOCKS_PER_SEC;
    clock_t start = clock();
    while(clock() - start < delay)
        //Sprawdzenie czy jest nacisniety klawisz
    if (klawisz jest nacisniety){
        kod_klawisza= //kod odczytanego klawisza;
        //czyszczenie bufora klawiszy
        break;
    }

 

PS. Ten kod powyżej to lekko zmodyfikowana modelowa pętla oczekująca z podręcznika.

Edytowane przez Pecet256

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Przyjemniej wygląda ta funkcja ruchu węża.
Można jeszcze sprawdzenie pola zrobić na switchu, będzie chyba czytelniej.

Pomyśl nad przepisaniem węża bez tablicy pomocniczej. To dobre ćwiczenie, żeby zobaczyć jak dane są ułożone w tablicy i jak się je modyfikuje.

Deklarujesz enuma, a w zasadzie nie korzystasz z niego w warunkach od wykonania akcji.
Skoro wejście na ścianę lub ogon nazywa się "sciana" i ma wartość 2, to w if-ie lepiej dać: if(wartosc!=sciana). Od razu widać o co chodzi w warunku, nie trzeba szukać co ta 2 oznacza.

Ostatni if można zamienić na else. Skoro najpierw sprawdzasz czy wartość jest różna od 2, to przeciwny warunek jest ==2.
Efekt ten sam ale innym nakładem działania programu. Teraz zostaną sprawdzone 2 warunki, przy konstrukcji if else jeden.
Jedyny sens robienia takiej konstrukcji, to jakby pod pierwszym if-em zmienna "wartosc" była modyfikowana.

 

Jeżeli chodzi o sprawdzanie upływu czasu, to nie wiem czy warto bawić się w zliczanie cykli zegara, czy jakiekolwiek funkcje jawnie korzystające z tego. Nie mam zaufania do takich mechanizmów przy procesorach, które zmieniają taktowanie na bieżąco. Trzeba zobaczyć czy jakieś dziwne rzeczy nie będą się działy.
W pracy pod linuksem korzystam z clock_gettime() z time.h, która zwraca strukturę z sekundami i nanosekundami od epoki ale pod windą chyba jej nie ma.
Można się rozejrzeć za nowszymi rozwiązaniami jak std::chrono ale to już faktycznie C++, a nie C i wymaga kompilatora w standardzie przynajmniej C++11, ewentualnie biblioteka boost::chrono (elementy z niej weszły do standardu 11).

Schemat wydaje się ok, pewnie rozbije się o szczegóły ;)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Poprzerabiałem trochę prototyp sterowania wzorując się na tym:

https://stackoverflow.com/questions/41600981/how-do-i-check-if-a-key-is-pressed-on-c/41601909

Cytat

As mentioned by others there's no cross platform way to do this, but on Windows you can do it like this:

The Code below checks if the key 'A' is down.


if(GetKeyState('A') & 0x8000/*Check if high-order bit is set (1 << 15)*/)
{
    // Do stuff
}

In case of shift or similar you will need to pass one of these: https://msdn.microsoft.com/de-de/library/windows/desktop/dd375731(v=vs.85).aspx


if(GetKeyState(VK_SHIFT) & 0x8000)
{
    // Shift down
}

The low-order bit indicates if key is toggled.


SHORT keyState = GetKeyState(VK_CAPITAL/*(caps lock)*/);
bool isToggled = keyState & 1;
bool isDown = keyState & 0x8000;

Oh and also don't forget to


#include <Windows.h>

Autor wypowiedzi:Frank S.

 

Zatem: Zrobiłem coś takiego:

#include <iostream>
#include <ctime>
#include <Windows.h>
int main()
{
    using namespace std;
    while(1){
    float secs;
    int kod_klawisza=0;
    secs=5;
    clock_t delay = secs * CLOCKS_PER_SEC;
    clock_t start = clock();
    while(clock() - start < delay){
        //Sprawdzenie czy jest nacisniety klawisz
    if(GetKeyState('W') & 0x8000)
    {
        cout << "Nacisnieto klawisz W";
        kod_klawisza =1;
        break;
    }
    if(GetKeyState('A') & 0x8000)
    {
        cout << "Nacisnieto klawisz A";
        kod_klawisza =2;
        break;
    }
    if(GetKeyState('S') & 0x8000)
    {
        cout << "Nacisnieto klawisz S";
        kod_klawisza =3;
        break;
    }
    if(GetKeyState('D') & 0x8000)
    {
        cout << "Nacisnieto klawisz D";
        kod_klawisza =4;
        break;
    }
    }
    cout<< "\ngotowe \n\a";

    switch(kod_klawisza){
        case 1:{
        cout << "W";
        break;
        }
        case 2:{
        cout << "A";
        break;
        }
        case 3:{
        cout << "S";
        break;
        }
        case 4:{
        cout << "D";
        break;
        }


    }
    }
    return 0;



}

 

Jeżeli jest to możliwe to przerobię to na funkcję zwracającą kod, na podstawie którego będzie zmiana wektora węża lub wyjście z gry. Jeżeli nie można tego przerobić na funkcję to wstawie coś w tym stylu do maina.

PS. Tak, wiem pętle nie zaznaczone, ale to prototyp.

 

Niestety wykorzystuje bibliotekę windows.h, zatem niestety nie jest to rozwiązanie przenośne. Ale i tak najpewniej zastosuję system ("cls") do czyszczenia konsoli.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Wcześniej użyta conio.h też nie jest przenośna z tego co wiem. Trzeba z tym żyć, że nie wszystko da się napisać uniwersalnie ale idzie to obchodzić na poziomie kompilacji (i tak pliku wykonalnego nie przeniesiesz) bawiąc się komendami preprocesora (ifdef) lub procesem kompilacji (np. w make będzie podstawiany odpowiedni plik obsługujący dany system operacyjny i jego biblioteki). Grunt żeby z sensem przygotować sobie interfejs (nazwy funkcji i argumenty), którym się będziesz posługiwał w głównej części programu oraz podział programu na pliki.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Właśnie skończyłem pisać sterowanie, i już można sterować wężem po planszy.

Pozostaje jeszcze do zrobienia generowanie pokarmu na planszy, ale tu wystarczą 2 liczby pseudolosowe i parę ifów.

Potem dorobię menu i inne "bajery"

Niestety system("cls") miga w czasie pracy programu - można to jakoś obeść?

Wklejam kod

#include <iostream>
#include <ctime>
#include <stdlib.h>
#include <Windows.h>

using namespace std;

//Stale - wielkosc planszy
    const int wiersze = 20;
    const int kolumny = 90;

//Deklaracja struktury segmentu weza;
struct segment
{
    int poz_wiersz;
    int poz_kolumna;
};
//Deklaracja struktury pokarmu do zebrania;
struct pokarm
{
    int poz_wiersz;
    int poz_kolumna;
};

//Enumerator - kierunki
enum kierunki{
    gora=0,
    lewo=1,
    dol=2,
    prawo=3,
    escape=9
};


void wyswietl(char plansza[wiersze][kolumny], kierunki wektor);
void pokazweza(segment snake [(wiersze-2)*(kolumny-2)],int dlugosc);//FUNKCJA TYMCZASOWA
int przesunweza(segment snake [(wiersze-2)*(kolumny-2)],int & dlugosc,char plansza[wiersze][kolumny],kierunki wektor, int & punkty);
void aktualizacja(char plansza[wiersze][kolumny],segment snake [(wiersze-2)*(kolumny-2)], int dlugosc);

int main()
{
    //waz jako tablica - rownanie wylicza makszymlna dlugosc weza;
    // segment o numerze 0 - glowa, pozostale - segmenty ogona;
    segment snake [(wiersze-2)*(kolumny-2)];
    //dlugosc weza - na poczatku gry glowa i 3 segmenty ogona
    int dlugosc = 4;
    int punkty = 0;

    //ustawianie poczatkowej pozycji weza
    int ustawianie=0;
    while(ustawianie<dlugosc){
        snake[ustawianie].poz_wiersz=1;
        snake[ustawianie].poz_kolumna=dlugosc+1-ustawianie;
        ustawianie=ustawianie+1;
    }


    //plansza gry
    char plansza [wiersze][kolumny];

    int wyswiersze = 0;
    int wyskolumny = 0;

    //===============================================================
    //Wypelnienie planszy
    while(wyswiersze<wiersze){
        while(wyskolumny<kolumny){
            plansza [wyswiersze][wyskolumny]=' ';
            wyskolumny = wyskolumny+1;
        }
        wyswiersze=wyswiersze+1;
        wyskolumny=0;
    }

    wyswiersze = 0;
    wyskolumny = 0;

    //ramka pozioma
    while (wyskolumny<kolumny){
        plansza[0][wyskolumny]= 'X';
        plansza[wiersze-1][wyskolumny]= 'X';
        wyskolumny=wyskolumny+1;
    }

    wyswiersze = 0;
    wyskolumny = 0;

    //ramka pionowa
    while (wyswiersze<wiersze){
        plansza[wyswiersze][0]= 'X';
        plansza[wyswiersze][kolumny-1]='X';
        wyswiersze=wyswiersze+1;
    }


    //Wstawianie weza do tablicy
    ustawianie=0;
    while(ustawianie<dlugosc){
            if(ustawianie==0){
                plansza[snake[ustawianie].poz_wiersz][snake[ustawianie].poz_kolumna]= 'G';
            }else{
                plansza[snake[ustawianie].poz_wiersz][snake[ustawianie].poz_kolumna]= 'O';
            }
        ustawianie=ustawianie+1;
    }

    //===============================================================

    //wyswietlenie planszy;
    cout << "Punkty: " << punkty << "          " << "Dlugosc weza: " << dlugosc<<endl;
    kierunki wektor= prawo;
    wyswietl(plansza, wektor);




    bool granie = 1;
    float secs=0.1a;
    int reakcja;

    while (granie==1){

        clock_t delay = secs * CLOCKS_PER_SEC;
        clock_t start = clock();
        while(clock() - start < delay){
            //Sprawdzenie czy jest nacisniety klawisz
            if((GetKeyState('W') & 0x8000) && (wektor!=gora))
            {
                wektor = gora;
                break;
            }
            if((GetKeyState('A') & 0x8000) && (wektor!=lewo))
            {
                wektor = lewo;
                break;
            }
            if((GetKeyState('S') & 0x8000) && (wektor!=dol))
            {

                wektor = dol;
                break;
            }
            if((GetKeyState('D') & 0x8000) && (wektor!=prawo))
            {
                wektor = prawo;
                break;
            }


        }
        reakcja = przesunweza(snake,dlugosc,plansza,wektor,punkty);
        if (reakcja==0){

            aktualizacja(plansza,snake,dlugosc);
            system("CLS");
            cout << "Punkty: " << punkty << "          " << "Dlugosc weza: " << dlugosc<<endl;
            wyswietl(plansza, wektor);
        }
        if (reakcja==1){
            granie=0;
        }
    }












    return 0;
}



void wyswietl(char plansza[wiersze][kolumny], kierunki wektor){
    //wyswietlenie planszy;
    int wyswiersze = 0;
    int wyskolumny = 0;

    while(wyswiersze<wiersze){
        while(wyskolumny<kolumny){
            if(plansza [wyswiersze][wyskolumny]!='G')
            {
                printf("%c", plansza [wyswiersze][wyskolumny]);
            }
            else{
                    if(wektor== gora){
                        printf ("A");
                    }
                    if(wektor== lewo){
                        printf ("<");
                    }
                    if(wektor== prawo){
                        printf (">");
                    }
                    if(wektor== dol){
                        printf ("V");
                    }

            }
            wyskolumny = wyskolumny+1;
        }
        cout << endl;
        wyswiersze=wyswiersze+1;
        wyskolumny=0;
    }

}

void pokazweza(segment snake [(wiersze-2)*(kolumny-2)],int dlugosc){
    int licznik=0;
    while(licznik<dlugosc){
        cout << "==========================================="<<endl;
        if(licznik==0){
            cout <<"GLOWA"<<endl;
        }
        else{
            cout << "SEGMENT no. " << licznik<<endl;
        }
        cout << "-------------------------------------------"<<endl;
        cout << "wartosc zmiennej poz_wiersz = " << snake[licznik].poz_wiersz<<endl;
        cout << "wartosc zmiennej poz_kolumna = " << snake[licznik].poz_kolumna<<endl;

        licznik=licznik+1;
    }

}

int przesunweza(segment snake [(wiersze-2)*(kolumny-2)],int & dlugosc,char plansza[wiersze][kolumny],kierunki wektor, int & punkty){
    int licznik;
    segment glowa;//Przechowuje wspozedne glowy weza
    glowa=snake[0];

    enum wyjscia{
    puste_pole=0,
    pokarm=1,
    sciana=2,//lub ogon
    };
    wyjscia wartosc;

    switch(wektor){
        case gora:
            glowa.poz_wiersz=glowa.poz_wiersz-1;
            break;
        case lewo:
            glowa.poz_kolumna=glowa.poz_kolumna-1;
            break;
        case dol:
            glowa.poz_wiersz=glowa.poz_wiersz+1;
            break;
        case prawo:
            glowa.poz_kolumna=glowa.poz_kolumna+1;
            break;
            }


    //Sprawdzanie na jakie pole jest przesuwana glowa weza
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]=='X'){
        wartosc=sciana;
        }else
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]=='O'){
        wartosc=sciana;
        }else
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]=='p'){
        wartosc=pokarm;
        }else
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]==' '){
        wartosc=puste_pole;
        }

    if(wartosc!=2){
        segment tymczasowa [dlugosc+2];
        licznik=0;
        while(licznik<dlugosc){//Kopiuje weza do tablicy tymczasowej
            tymczasowa[licznik]=snake[licznik];

            licznik=licznik+1;
        }
        snake[0]=glowa;
        licznik=1;
        while(licznik<dlugosc){
            snake[licznik]=tymczasowa[licznik-1];
            licznik=licznik+1;
        }
        if(wartosc==1){
            snake[dlugosc]=tymczasowa[dlugosc-1];
            dlugosc=dlugosc+1;
            punkty=punkty+1;
        }
    }

    if (wartosc==2){//Zwraca 2 gdy glowa weza uderza o sciane lub o ogon
        return 1;
    }
    return 0;

}

void aktualizacja(char plansza[wiersze][kolumny],segment snake [(wiersze-2)*(kolumny-2)], int dlugosc){
    int wyswiersze = 0;
    int wyskolumny = 0;

    //===============================================================
    //Wypelnienie planszy
    while(wyswiersze<wiersze){
        while(wyskolumny<kolumny){
            plansza [wyswiersze][wyskolumny]=' ';
            wyskolumny = wyskolumny+1;
        }
        wyswiersze=wyswiersze+1;
        wyskolumny=0;
    }

    wyswiersze = 0;
    wyskolumny = 0;

    //ramka pozioma
    while (wyskolumny<kolumny){
        plansza[0][wyskolumny]= 'X';
        plansza[wiersze-1][wyskolumny]= 'X';
        wyskolumny=wyskolumny+1;
    }

    wyswiersze = 0;
    wyskolumny = 0;

    //ramka pionowa
    while (wyswiersze<wiersze){
        plansza[wyswiersze][0]= 'X';
        plansza[wyswiersze][kolumny-1]='X';
        wyswiersze=wyswiersze+1;
    }

    //Wstawianie weza do tablicy
    int ustawianie=0;
    while(ustawianie<dlugosc){
            if(ustawianie==0){
                plansza[snake[ustawianie].poz_wiersz][snake[ustawianie].poz_kolumna]= 'G';
            }else{
                plansza[snake[ustawianie].poz_wiersz][snake[ustawianie].poz_kolumna]= 'O';
            }
        ustawianie=ustawianie+1;
    }



}

 

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach
33 minuty temu, Pecet256 napisał:

Niestety system("cls") miga w czasie pracy programu - można to jakoś obeść?

Bawiąc się funkcjami z conio.h? Z tego co pamiętam, to była tam możliwość wstawiania znaków w wybrane miejsce ekranu, więc nie trzeba by czyścić. Ewentualnie są funkcje czyszczące ekran bez wywoływania zewnętrznego programu.

Można też spróbować załadować napis całej tablicy do bufora i wypluć wszystko na raz, zamiast pisać po znaku. Powinno szybciej się wykonać i być może miganie będzie mniej widoczne.

Edytowane przez Bono[UG]

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Mam pytanie - czy jako bufor może posłużyć duży napis - tablica, czyli tablica typu char zakończona znakiem NUL? Czy muszę zastosować specjalny typ z jakiejś biblioteki?

 

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Cokolwiek, co użyta metoda wypisywania na ekran łyknie. Tablica powinna być ok.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

[long post]

Dodałem generowanie pokarmu oraz prawie całkowicie usunąłem migotanie poprzez zastosowanie bufora - tablicy.

Co do generowania pokarmu, to mam mały problem. Dla ułatwienia gry chcę, aby pokarm nie generował się na polach bezspośrednio przy ścianach, ale pomimo ifów, tam się generuje (zobacz kod funkcji na końcu kodu).

Dalsze plany to menu główne, pauza, plansza najwyższych wyników, gdzie możnabyłoby wpisać swoje imię (zapis/odczyt do/z pliku) oraz odczyt ciekawszych plansz z plików (bariery na środku planszy ułożone w różne sposoby).

Grać się da, nawet fajnie, gdyż popracowałem nad sterowaniem.

Odnoszę wrażenie, że wraz ze wzrostem długości węża gra chodzi wolniej - czy to złudzenie optyczne?

wstawiam kod

#include <iostream>
#include <ctime>
#include <stdlib.h>
#include <Windows.h>

using namespace std;

//Stale - wielkosc planszy
    const int wiersze = 20;
    const int kolumny = 90;


//Deklaracja struktury segmentu weza;
struct segment
{
    int poz_wiersz;
    int poz_kolumna;
};
//Deklaracja struktury pokarmu do zebrania;
struct pokarm
{
    int poz_wiersz;
    int poz_kolumna;
};

pokarm karmaweza;

//Enumerator - kierunki
enum kierunki{
    gora=0,
    lewo=1,
    dol=2,
    prawo=3,
    escape=9
};


void wyswietl(char plansza[wiersze][kolumny], kierunki wektor);
void pokazweza(segment snake [(wiersze-2)*(kolumny-2)],int dlugosc);//FUNKCJA TYMCZASOWA
int przesunweza(segment snake [(wiersze-2)*(kolumny-2)],int & dlugosc,char plansza[wiersze][kolumny],kierunki wektor, int & punkty);
void aktualizacja(char plansza[wiersze][kolumny],segment snake [(wiersze-2)*(kolumny-2)], int dlugosc);
void generujpokarm(char plansza[wiersze][kolumny]);

int main()
{
    srand( time( NULL ) );
    //waz jako tablica - rownanie wylicza makszymlna dlugosc weza;
    // segment o numerze 0 - glowa, pozostale - segmenty ogona;
    segment snake [(wiersze-2)*(kolumny-2)];
    //dlugosc weza - na poczatku gry glowa i 3 segmenty ogona
    int dlugosc = 4;
    int punkty = 0;

    //ustawianie poczatkowej pozycji weza
    int ustawianie=0;
    while(ustawianie<dlugosc){
        snake[ustawianie].poz_wiersz=1;
        snake[ustawianie].poz_kolumna=dlugosc+1-ustawianie;
        ustawianie=ustawianie+1;
    }


    //plansza gry
    char plansza [wiersze][kolumny];

    int wyswiersze = 0;
    int wyskolumny = 0;

    //===============================================================
    //Wypelnienie planszy
    while(wyswiersze<wiersze){
        while(wyskolumny<kolumny){
            plansza [wyswiersze][wyskolumny]=' ';
            wyskolumny = wyskolumny+1;
        }
        wyswiersze=wyswiersze+1;
        wyskolumny=0;
    }

    wyswiersze = 0;
    wyskolumny = 0;

    //ramka pozioma
    while (wyskolumny<kolumny){
        plansza[0][wyskolumny]= 'X';
        plansza[wiersze-1][wyskolumny]= 'X';
        wyskolumny=wyskolumny+1;
    }

    wyswiersze = 0;
    wyskolumny = 0;

    //ramka pionowa
    while (wyswiersze<wiersze){
        plansza[wyswiersze][0]= 'X';
        plansza[wyswiersze][kolumny-1]='X';
        wyswiersze=wyswiersze+1;
    }


    //Wstawianie weza do tablicy
    ustawianie=0;
    while(ustawianie<dlugosc){
            if(ustawianie==0){
                plansza[snake[ustawianie].poz_wiersz][snake[ustawianie].poz_kolumna]= 'G';
            }else{
                plansza[snake[ustawianie].poz_wiersz][snake[ustawianie].poz_kolumna]= 'O';
            }
        ustawianie=ustawianie+1;
    }

    //===============================================================

    //wyswietlenie planszy;
    cout << "Punkty: " << punkty << "          " << "Dlugosc weza: " << dlugosc<<endl;
    kierunki wektor= prawo;
    generujpokarm(plansza);
    wyswietl(plansza, wektor);



    bool granie = 1;
    float secs=0.1;
    int reakcja;

    while (granie==1){

        clock_t delay = secs * CLOCKS_PER_SEC;
        clock_t start = clock();
        while(clock() - start < delay){
            //Sprawdzenie czy jest nacisniety klawisz
            if(((GetKeyState('W') & 0x8000) && (wektor!=gora)) && (wektor!=dol))
            {
                wektor = gora;
                break;
            }
            if(((GetKeyState('A') & 0x8000) && (wektor!=lewo)) && (wektor!=prawo))
            {
                wektor = lewo;
                break;
            }
            if(((GetKeyState('S') & 0x8000) && (wektor!=dol)) && (wektor!=gora))
            {

                wektor = dol;
                break;
            }
            if(((GetKeyState('D') & 0x8000) && (wektor!=prawo)) && (wektor!=lewo))
            {
                wektor = prawo;
                break;
            }


        }
        reakcja = przesunweza(snake,dlugosc,plansza,wektor,punkty);

        if ((reakcja==0) || (reakcja==2)){
            if(reakcja==2){
                generujpokarm(plansza);
            }
            aktualizacja(plansza,snake,dlugosc);
            system("CLS");
            cout << "Punkty: " << punkty << "          " << "Dlugosc weza: " << dlugosc<<endl;
            wyswietl(plansza, wektor);
        }
        if (reakcja==1){
            granie=0;
        }

    }












    return 0;
}



void wyswietl(char plansza[wiersze][kolumny], kierunki wektor){
    //wyswietlenie planszy;
    int wyswiersze = 0;
    int wyskolumny = 0;
    long wymiartablicy;
    wymiartablicy = (wiersze*(kolumny+2));
    char ekran [wymiartablicy];
    int licznik=0;


    while(wyswiersze<wiersze){
        while(wyskolumny<kolumny){
            if(plansza [wyswiersze][wyskolumny]!='G')
            {
                ekran[licznik]=plansza [wyswiersze][wyskolumny];
            }
            else{
                    if(wektor== gora){
                        ekran[licznik]='A';
                    }
                    if(wektor== lewo){
                        ekran[licznik]='<';
                    }
                    if(wektor== prawo){
                        ekran[licznik]='>';
                    }
                    if(wektor== dol){
                        ekran[licznik]='V';
                    }

            }
            wyskolumny = wyskolumny+1;
            licznik=licznik+1;
        }
        ekran[licznik]='\n';
        licznik=licznik+1;
        wyswiersze=wyswiersze+1;
        wyskolumny=0;
    }
    cout << ekran;

}

void pokazweza(segment snake [(wiersze-2)*(kolumny-2)],int dlugosc){
    int licznik=0;
    while(licznik<dlugosc){
        cout << "==========================================="<<endl;
        if(licznik==0){
            cout <<"GLOWA"<<endl;
        }
        else{
            cout << "SEGMENT no. " << licznik<<endl;
        }
        cout << "-------------------------------------------"<<endl;
        cout << "wartosc zmiennej poz_wiersz = " << snake[licznik].poz_wiersz<<endl;
        cout << "wartosc zmiennej poz_kolumna = " << snake[licznik].poz_kolumna<<endl;

        licznik=licznik+1;
    }

}

int przesunweza(segment snake [(wiersze-2)*(kolumny-2)],int & dlugosc,char plansza[wiersze][kolumny],kierunki wektor, int & punkty){
    int licznik;
    segment glowa;//Przechowuje wspozedne glowy weza
    glowa=snake[0];

    enum wyjscia{
    puste_pole=0,
    pokarm=1,
    sciana=2,//lub ogon
    };
    wyjscia wartosc;

    switch(wektor){
        case gora:
            glowa.poz_wiersz=glowa.poz_wiersz-1;
            break;
        case lewo:
            glowa.poz_kolumna=glowa.poz_kolumna-1;
            break;
        case dol:
            glowa.poz_wiersz=glowa.poz_wiersz+1;
            break;
        case prawo:
            glowa.poz_kolumna=glowa.poz_kolumna+1;
            break;
            }


    //Sprawdzanie na jakie pole jest przesuwana glowa weza
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]=='X'){
        wartosc=sciana;
        }else
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]=='O'){
        wartosc=sciana;
        }else
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]=='p'){
        wartosc=pokarm;
        }else
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]==' '){
        wartosc=puste_pole;
        }

    if(wartosc!=2){
        segment tymczasowa [dlugosc+2];
        licznik=0;
        while(licznik<dlugosc){//Kopiuje weza do tablicy tymczasowej
            tymczasowa[licznik]=snake[licznik];

            licznik=licznik+1;
        }
        snake[0]=glowa;
        licznik=1;
        while(licznik<dlugosc){
            snake[licznik]=tymczasowa[licznik-1];
            licznik=licznik+1;
        }
        if(wartosc==1){
            snake[dlugosc]=tymczasowa[dlugosc-1];
            dlugosc=dlugosc+1;
            punkty=punkty+1;
        }
    }

    if (wartosc==2){//Zwraca 2 gdy glowa weza uderza o sciane lub o ogon
        return 1;
    }
    if (wartosc==1){
        return 2;
    }
    return 0;

}

void aktualizacja(char plansza[wiersze][kolumny],segment snake [(wiersze-2)*(kolumny-2)], int dlugosc){
    int wyswiersze = 0;
    int wyskolumny = 0;

    //===============================================================
    //Wypelnienie planszy
    while(wyswiersze<wiersze){
        while(wyskolumny<kolumny){
            plansza [wyswiersze][wyskolumny]=' ';
            wyskolumny = wyskolumny+1;
        }
        wyswiersze=wyswiersze+1;
        wyskolumny=0;
    }

    wyswiersze = 0;
    wyskolumny = 0;

    //ramka pozioma
    while (wyskolumny<kolumny){
        plansza[0][wyskolumny]= 'X';
        plansza[wiersze-1][wyskolumny]= 'X';
        wyskolumny=wyskolumny+1;
    }

    wyswiersze = 0;
    wyskolumny = 0;

    //ramka pionowa
    while (wyswiersze<wiersze){
        plansza[wyswiersze][0]= 'X';
        plansza[wyswiersze][kolumny-1]='X';
        wyswiersze=wyswiersze+1;
    }

    //Wstawianie weza do tablicy
    int ustawianie=0;
    while(ustawianie<dlugosc){
            if(ustawianie==0){
                plansza[snake[ustawianie].poz_wiersz][snake[ustawianie].poz_kolumna]= 'G';
            }else{
                plansza[snake[ustawianie].poz_wiersz][snake[ustawianie].poz_kolumna]= 'O';
            }
        ustawianie=ustawianie+1;
    }
    plansza[karmaweza.poz_wiersz][karmaweza.poz_kolumna]= 'p';



}

void generujpokarm(char plansza[wiersze][kolumny]){
    pokarm karma;

    do{
        do{
            karma.poz_kolumna=rand();
        }while ((karma.poz_kolumna<1 ) || (karma.poz_kolumna>(kolumny-2)));

        do{
            karma.poz_wiersz=rand();
        }while ((karma.poz_wiersz<1 ) || (karma.poz_wiersz>(wiersze-2)));

    }while(plansza[karma.poz_wiersz][karma.poz_kolumna] != ' ');
    karmaweza.poz_wiersz=karma.poz_wiersz;
    karmaweza.poz_kolumna=karma.poz_kolumna;

}
//

I jeszcze jedno pytanie. Mówiłeś, że wolałbyś przechowywać węża jako współrzędne głowy i końcówki ogona - zastanawiam się jak. Wyobraź sobie 2 węże o takich samych współrzędnych głowy i końcówki ogona. Jeden ma kształt litery U, a drugi kształt P w cyrylicy (czyli U odwrócone o 180 stopni). Jak chciałbyś to zrobić.

PS. Przepraszam za strukturę globalną dla wszystkich funkcji.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach
46 minut temu, Pecet256 napisał:

Co do generowania pokarmu, to mam mały problem. Dla ułatwienia gry chcę, aby pokarm nie generował się na polach bezspośrednio przy ścianach, ale pomimo ifów, tam się generuje (zobacz kod funkcji na końcu kodu).

Popatrz jakie masz warunki, a jak wygląda plansza.
Warunek "pozycja<1" jest spełniony tylko dla przypadku wylosowania 0, czyli w tym przypadku ściany/brzegu planszy.
Podobnie "pozycja>rozmiar_tablicy-2". Jeżeli tablica ma rozmiar 10, to możesz się odwołać do indeksów 0-9. Sprawdzasz warunek dla liczb > od 8, czyli znowu tylko ściana nie spełnia warunku.

Sprawę powinny załatwić nierówności tępe, czyli <= i >=, ewentualnie trzeba skorygować indeksy o 1.

Widzę tutaj inny problem związany z wydajnością i możliwym powieszeniem programu.
Funkcja rand zwraca wartości od 0 do mówiąc oględnie dużo. Potrzebujesz z tego bardzo małego wycinka wartości, szansa że trafisz w poprawne nie jest tak duża, więc pętle mogą mielić się dosyć długo (w teorii to i w nieskończoność).
W opisie funkcji masz podane przykłady jak losować wartości z przedziału 0-X przy wykorzystaniu działania modulo. Tutaj warto jeszcze zadbać o przesunięcie wartości. Dla planszy o rozmiarze 10, chcesz wybrać pozycję z przedziału [2;7], to jest 6 wartości (10-2xściana-2xpole_obok_ściany). Wystarczy losować z przedziału 0-5 i zwiększyć wartość o 2 (za dużo podpowiadam ;) ), odpadają wtedy te dwie pierwsze pętle, bo nie wylosujesz spoza przedziału, który chcesz. Kolejnej pętli i warunku nie unikniesz.

Godzinę temu, Pecet256 napisał:

Odnoszę wrażenie, że wraz ze wzrostem długości węża gra chodzi wolniej - czy to złudzenie optyczne?

Może tak być, choćby ze względu na losowanie pokarmu. Im dłuższy wąż, tym mniej wolnych pól. Można pokombinować jak obejść ten problem ale to może później jakby był problem z wylosowaniem kolejnego pokarmu przy większym wypełnieniu planszy.

Przy powiększającym się wężu również przepisywanie tablicy z nim trwa dłużej, choć nie powinno to w tym przypadku drastycznie wpływać na wydajność (może przy jakiejś dużej planszy).

1 godzinę temu, Pecet256 napisał:

I jeszcze jedno pytanie. Mówiłeś, że wolałbyś przechowywać węża jako współrzędne głowy i końcówki ogona - zastanawiam się jak. Wyobraź sobie 2 węże o takich samych współrzędnych głowy i końcówki ogona. Jeden ma kształt litery U, a drugi kształt P w cyrylicy (czyli U odwrócone o 180 stopni). Jak chciałbyś to zrobić.

Nie jako tylko głowę i ogon, a jako listę, bo wtedy operacje przesunięcia węża sprowadzałyby się na manipulacji głową i ogonem, środka nie trzeba zmieniać. Ale nadal trzeba pamiętać środek, żeby wiedzieć gdzie się znajduje wąż i jaki ma kształt.
Np. mamy węża na pozycjach: (3,4)(3,5)(3,6)(3,7). Powiedzmy, że wykonamy ruch w dół, wtedy na początek listy dostawiamy nowy element i będzie to wyglądało tak: (4,4)(3,4)(3,5)(3,6)(3,7). Jeżeli wąż nic nie zjadł, to nie wydłużył się, więc trzeba uciąć ogon: (4,4)(3,4)(3,5)(3,6). Jeżeli coś by zjadł, to wystarczy samo dostawienie nowej głowy. Trochę więcej kombinowania jakby był jakiś super pokarm, który mocniej wydłuża ale rozbijając to na kilka ruchów da się łatwo ogarnąć licznikiem posiłku (np. przy zwykłym pokarmie zwiększasz licznik o 1, przy solidniejszym o 2, 3 czy ile się tam wymyśli, przy przesuwaniu węża jeżeli licznik !=0 to nie obcinasz ogona i zmniejszasz licznik o 1).

1 godzinę temu, Pecet256 napisał:

prawie całkowicie usunąłem migotanie poprzez zastosowanie bufora - tablicy.

Widzę tu jeszcze pole do poprawy.
Najpierw czyścisz ekran, a potem zapełniasz bufor i go wyświetlasz. Między operacją czyszczenia, a wyświetlenia mija trochę czasu na przerzucenie danych do bufora.
Lepiej najpierw załadować do bufora, a potem wyczyścić ekran i wyświetlić bufor, będzie mniejsza przerwa. Wymaga to przekonstruowania funkcji wyświetlającej, może zawierać wszystkie operacje związane z aktualizacją obrazu (czyszczenie, aktualny wynik, plansza) lub zwracać przygotowany bufor do wypisania.

Drobna poprawka, to if-y od rysowania kierunku ruchu węża. Niepotrzebnie za każdym razem są sprawdzane wszystkie warunki. Jeżeli pierwszy jest spełniony, to po co kolejne też sprawdzać? Do zastosowania konstrukcja if else if ... lub switch.
 

Chyba zgubiłeś wcześniejsze wyjście z gry.

Jest jeszcze kilka innych miejsc, gdzie warunki niekoniecznie są sensownie ustawione lub można trochę wydajność poprawić ale to na potem.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Zmodyfikowałem generowanie pokarmu oraz dodałem opcję super pokarmu (z fajnym sposobem liczenia punktów)

Co do esc - jeszcze nie ma, będzi wyświetlać plansze pauzy z możliwością przerwania gry.

 

#include <iostream>
#include <ctime>
#include <stdlib.h>
#include <Windows.h>
#include <fstream>

using namespace std;

//Stale - wielkosc planszy
    const int wiersze = 20;
    const int kolumny = 90;

    const int limitwynikow = 10;
//Deklaracja struktury segmentu weza;
struct segment
{
    int poz_wiersz;
    int poz_kolumna;
};
//Deklaracja struktury pokarmu do zebrania;
struct pokarm
{
    int poz_wiersz;
    int poz_kolumna;
};

pokarm karmaweza;

int super=0;

//Enumerator - kierunki
enum kierunki{
    gora=0,
    lewo=1,
    dol=2,
    prawo=3,
    escape=9
};


void wyswietl(char plansza[wiersze][kolumny], kierunki wektor);
void pokazweza(segment snake [(wiersze-2)*(kolumny-2)],int dlugosc);//FUNKCJA TYMCZASOWA
int przesunweza(segment snake [(wiersze-2)*(kolumny-2)],int & dlugosc,char plansza[wiersze][kolumny],kierunki wektor, int & punkty, int & wzrost);
void aktualizacja(char plansza[wiersze][kolumny],segment snake [(wiersze-2)*(kolumny-2)], int dlugosc);
void generujpokarm(char plansza[wiersze][kolumny]);

int main()
{
    srand( time( NULL ) );
    //waz jako tablica - rownanie wylicza makszymlna dlugosc weza;
    // segment o numerze 0 - glowa, pozostale - segmenty ogona;
    segment snake [(wiersze-2)*(kolumny-2)];
    //dlugosc weza - na poczatku gry glowa i 3 segmenty ogona
    int dlugosc = 4;
    int punkty = 0;

    //ustawianie poczatkowej pozycji weza
    int ustawianie=0;
    while(ustawianie<dlugosc){
        snake[ustawianie].poz_wiersz=1;
        snake[ustawianie].poz_kolumna=dlugosc+1-ustawianie;
        ustawianie=ustawianie+1;
    }


    //plansza gry
    char plansza [wiersze][kolumny];

    int wyswiersze = 0;
    int wyskolumny = 0;

    //===============================================================
    //Wypelnienie planszy
    while(wyswiersze<wiersze){
        while(wyskolumny<kolumny){
            plansza [wyswiersze][wyskolumny]=' ';
            wyskolumny = wyskolumny+1;
        }
        wyswiersze=wyswiersze+1;
        wyskolumny=0;
    }

    wyswiersze = 0;
    wyskolumny = 0;

    //ramka pozioma
    while (wyskolumny<kolumny){
        plansza[0][wyskolumny]= 'X';
        plansza[wiersze-1][wyskolumny]= 'X';
        wyskolumny=wyskolumny+1;
    }

    wyswiersze = 0;
    wyskolumny = 0;

    //ramka pionowa
    while (wyswiersze<wiersze){
        plansza[wyswiersze][0]= 'X';
        plansza[wyswiersze][kolumny-1]='X';
        wyswiersze=wyswiersze+1;
    }


    //Wstawianie weza do tablicy
    ustawianie=0;
    while(ustawianie<dlugosc){
            if(ustawianie==0){
                plansza[snake[ustawianie].poz_wiersz][snake[ustawianie].poz_kolumna]= 'G';
            }else{
                plansza[snake[ustawianie].poz_wiersz][snake[ustawianie].poz_kolumna]= 'O';
            }
        ustawianie=ustawianie+1;
    }

    //===============================================================

    //wyswietlenie planszy;
    cout << "Punkty: " << punkty << "          " << "Dlugosc weza: " << dlugosc<<endl;
    kierunki wektor= prawo;
    generujpokarm(plansza);
    wyswietl(plansza, wektor);



    bool granie = 1;
    float secs=0.1;
    int reakcja;
    int wzrost;

    while (granie==1){

        clock_t delay = secs * CLOCKS_PER_SEC;
        clock_t start = clock();
        while(clock() - start < delay){
            //Sprawdzenie czy jest nacisniety klawisz
            if(((GetKeyState('W') & 0x8000) && (wektor!=gora)) && (wektor!=dol))
            {
                wektor = gora;
                break;
            }
            if(((GetKeyState('A') & 0x8000) && (wektor!=lewo)) && (wektor!=prawo))
            {
                wektor = lewo;
                break;
            }
            if(((GetKeyState('S') & 0x8000) && (wektor!=dol)) && (wektor!=gora))
            {

                wektor = dol;
                break;
            }
            if(((GetKeyState('D') & 0x8000) && (wektor!=prawo)) && (wektor!=lewo))
            {
                wektor = prawo;
                break;
            }


        }
        reakcja = przesunweza(snake,dlugosc,plansza,wektor,punkty,wzrost);

        if ((reakcja==0) || (reakcja==2)){
            if(reakcja==2){
                generujpokarm(plansza);
            }
            aktualizacja(plansza,snake,dlugosc);
            system("CLS");
            cout << "Punkty: " << punkty << "          " << "Dlugosc weza: " << dlugosc<<endl;
            wyswietl(plansza, wektor);
        }
        if (reakcja==1){
            granie=0;
        }

    }

    system("CLS");
    cout << "             GAME OVER"<<endl;
    cout<< "Waz uderzyl w sciane lub we wlasny ogon"<<endl;
    cout<< "Wynik " <<punkty<<" punktow" <<endl;

    int znak;
    //FILE *plik = fopen( "wyniki.txt", "r" );
    //znak = getc( plik );

    //fclose( plik );

    cout<< "Nacisnij klawisz ENTER"<<endl;
    cin.get();





    return 0;
}



void wyswietl(char plansza[wiersze][kolumny], kierunki wektor){
    //wyswietlenie planszy;
    int wyswiersze = 0;
    int wyskolumny = 0;
    long wymiartablicy;
    wymiartablicy = (wiersze*(kolumny+2));
    char ekran [wymiartablicy];
    int licznik=0;


    while(wyswiersze<wiersze){
        while(wyskolumny<kolumny){
            if(plansza [wyswiersze][wyskolumny]!='G')
            {
                ekran[licznik]=plansza [wyswiersze][wyskolumny];
            }
            else{
                    if(wektor== gora){
                        ekran[licznik]='A';
                    }
                    if(wektor== lewo){
                        ekran[licznik]='<';
                    }
                    if(wektor== prawo){
                        ekran[licznik]='>';
                    }
                    if(wektor== dol){
                        ekran[licznik]='V';
                    }

            }
            wyskolumny = wyskolumny+1;
            licznik=licznik+1;
        }
        ekran[licznik]='\n';
        licznik=licznik+1;
        wyswiersze=wyswiersze+1;
        wyskolumny=0;
    }
    cout << ekran;

}

void pokazweza(segment snake [(wiersze-2)*(kolumny-2)],int dlugosc){
    int licznik=0;
    while(licznik<dlugosc){
        cout << "==========================================="<<endl;
        if(licznik==0){
            cout <<"GLOWA"<<endl;
        }
        else{
            cout << "SEGMENT no. " << licznik<<endl;
        }
        cout << "-------------------------------------------"<<endl;
        cout << "wartosc zmiennej poz_wiersz = " << snake[licznik].poz_wiersz<<endl;
        cout << "wartosc zmiennej poz_kolumna = " << snake[licznik].poz_kolumna<<endl;

        licznik=licznik+1;
    }

}

int przesunweza(segment snake [(wiersze-2)*(kolumny-2)],int & dlugosc,char plansza[wiersze][kolumny],kierunki wektor, int & punkty, int & wzrost){
    int licznik;
    segment glowa;//Przechowuje wspozedne glowy weza
    glowa=snake[0];

    enum wyjscia{
    puste_pole=0,
    pokarm=1,
    sciana=2,//lub ogon
    super=3,
    };
    wyjscia wartosc;

    switch(wektor){
        case gora:
            glowa.poz_wiersz=glowa.poz_wiersz-1;
            break;
        case lewo:
            glowa.poz_kolumna=glowa.poz_kolumna-1;
            break;
        case dol:
            glowa.poz_wiersz=glowa.poz_wiersz+1;
            break;
        case prawo:
            glowa.poz_kolumna=glowa.poz_kolumna+1;
            break;
            }


    //Sprawdzanie na jakie pole jest przesuwana glowa weza
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]=='X'){
        wartosc=sciana;
        }else
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]=='O'){
        wartosc=sciana;
        }else
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]=='p'){
        wartosc=pokarm;
        }else
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]==' '){
        wartosc=puste_pole;
        }
    if (plansza[glowa.poz_wiersz][glowa.poz_kolumna]=='s'){
        wartosc=super;
        }

    //=====================================================

    if(wartosc==1){
        wzrost=wzrost+1;
        punkty=punkty+1;
    }
    if(wartosc==3){
        int temp = ((rand() % 4 )+5);
        wzrost = temp;
        punkty=punkty+1+(temp*temp);
    }

    if(wartosc!=2){
        segment tymczasowa [dlugosc+2];
        licznik=0;
        while(licznik<dlugosc){//Kopiuje weza do tablicy tymczasowej
            tymczasowa[licznik]=snake[licznik];

            licznik=licznik+1;
        }
        snake[0]=glowa;
        licznik=1;
        while(licznik<dlugosc){
            snake[licznik]=tymczasowa[licznik-1];
            licznik=licznik+1;
        }
        if(wzrost>=1){
            snake[dlugosc]=tymczasowa[dlugosc-1];
            dlugosc=dlugosc+1;
            wzrost=wzrost-1;
        }
    }

    if (wartosc==2){//Zwraca 2 gdy glowa weza uderza o sciane lub o ogon
        return 1;
    }
    if (wartosc==1){
        return 2;
    }
    if (wartosc==3){
        return 2;
    }
    return 0;

}

void aktualizacja(char plansza[wiersze][kolumny],segment snake [(wiersze-2)*(kolumny-2)], int dlugosc){
    int wyswiersze = 0;
    int wyskolumny = 0;

    //===============================================================
    //Wypelnienie planszy
    while(wyswiersze<wiersze){
        while(wyskolumny<kolumny){
            plansza [wyswiersze][wyskolumny]=' ';
            wyskolumny = wyskolumny+1;
        }
        wyswiersze=wyswiersze+1;
        wyskolumny=0;
    }

    wyswiersze = 0;
    wyskolumny = 0;

    //ramka pozioma
    while (wyskolumny<kolumny){
        plansza[0][wyskolumny]= 'X';
        plansza[wiersze-1][wyskolumny]= 'X';
        wyskolumny=wyskolumny+1;
    }

    wyswiersze = 0;
    wyskolumny = 0;

    //ramka pionowa
    while (wyswiersze<wiersze){
        plansza[wyswiersze][0]= 'X';
        plansza[wyswiersze][kolumny-1]='X';
        wyswiersze=wyswiersze+1;
    }

    //Wstawianie weza do tablicy
    int ustawianie=0;
    while(ustawianie<dlugosc){
            if(ustawianie==0){
                plansza[snake[ustawianie].poz_wiersz][snake[ustawianie].poz_kolumna]= 'G';
            }else{
                plansza[snake[ustawianie].poz_wiersz][snake[ustawianie].poz_kolumna]= 'O';
            }
        ustawianie=ustawianie+1;
    }

    if (super==0){
        plansza[karmaweza.poz_wiersz][karmaweza.poz_kolumna]= 'p';
    }else{
        plansza[karmaweza.poz_wiersz][karmaweza.poz_kolumna]= 's';
    }



}

void generujpokarm(char plansza[wiersze][kolumny]){


    srand( time( NULL ) );
    long wybrane_pole;

    pokarm pola_pokarmu [(wiersze*kolumny)];

    int licznik_wierszy=0;
    int licznik_kolumn;
    long licznik_pol=0;

    while(licznik_wierszy<wiersze){
            licznik_kolumn=0;
            while(licznik_kolumn<kolumny){
                if(plansza[licznik_wierszy][licznik_kolumn]==' '){
                    if(((((licznik_wierszy!=0)&&(licznik_wierszy!=wiersze-1))&&(licznik_kolumn!=0))&&(licznik_kolumn!=kolumny))){
                        if((((plansza[licznik_wierszy][licznik_kolumn+1]==' ')&&(plansza[licznik_wierszy][licznik_kolumn-1]==' '))&&
                            (plansza[licznik_wierszy+1][licznik_kolumn]==' '))&&(plansza[licznik_wierszy-1][licznik_kolumn]==' ')){

                                pola_pokarmu[licznik_pol].poz_kolumna=licznik_kolumn;
                                pola_pokarmu[licznik_pol].poz_wiersz=licznik_wierszy;
                                licznik_pol=licznik_pol+1;
                            }
                    }

                }
                licznik_kolumn=licznik_kolumn+1;
            }

        licznik_wierszy=licznik_wierszy+1;
    }
    wybrane_pole= (rand() % licznik_pol);

    int temp;
    temp = (rand() % 100 );
    if(temp<80){
        super=0;
    }else{
        super=1;
    }



    karmaweza.poz_wiersz=pola_pokarmu[wybrane_pole].poz_wiersz;
    karmaweza.poz_kolumna=pola_pokarmu[wybrane_pole].poz_kolumna;

}
//

Teraz chcę dodać planszę 10 najwyższych wyników.

Chodzi o to, że na końcu rozgrywki program ma załadować plik z najwyższymi wynikami, dopisać wynik gracza (i imie wpisane przez gracza), posortować, wyświetlić na ekranie, oraz zapisać w pliku, nadpisując stare dane ( W pliku zawsze ma być 10 wyników i 10 imion). W menu gry będzie też opcja pokazania 10 aktualnych najlepszych wyników.

Przykładowy plik prezentuje się następująco

12|gracz1/
24|gracz2/
56|gracz3/
90|gracz4
122|gracz5/
91|gracz6/
13|gracz7/
99|gracz8/
223|gracz9/
100|gracz10/

| rozdziela wynik od imienia gracza, / rodziela pozycje.

Całość ma się załadować do 2 tablic - int wyniki [11] oraz char imiona [50][11]. (A może tablica struktur...)

Chciałbym zastosować odczyt znak po znaku i taki sam zapis. Nie wiem jak sobie poradzić z tym, że liczby nie są zapisane binarnie, a dziesiętnie jako znaki.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Odnośnie generowania pokarmu, to niepotrzebnie masz pętle idące po krawędzi planszy.
Skoro za chwilę i tak wycinasz to warunkiem, to nie lepiej zacząć pętle od wiersza i kolumny o numerze 1, a zakończyć od maksmymalnej-1?
Robisz warunek na rzeczy niezmienne w programie, bo granica planszy zawsze jest w tym samym miejscu, czyli na maksymalnych indeksach tablicy, 0 kolumna i wiersz oraz wiersze-1 i kolumny-1.

srand nie ma sensu przy każdym wywołaniu funkcji. Wystarczy raz na początku programu.
 

Sposobów na przechowywanie danych są tysiące. Ja pewnie bym zrobił jakąś strukturę typu para (wynik, imię), do tego funkcja porównująca, żeby dało się posortować z lekką sugestią jej zdefiniowania w ciele struktury (taka namiastka klasy ;) ).

A zapis do pliku, to zależy na czym ci zależy. Czy plik ma być czytelny dla człowieka, czy wygodny w użyciu w programie.
Tekstowy będzie prosty dla człowieka ale trzeba się trochę namęczyć z odczytem w programie. Trzeba się zdecydować jakimi narzędziami się posłużyć, czym będziesz chciał operować na plikach (read/write, fscanf/fprinf, strumienie...). Jak się ustali sposób operowania, to będzie łatwiej ustawić format danych w pliku.
Binarny, przy odpowiednich strukturach sprowadzi się do zapisu i odczytu całej tablicy na raz.

 

Odpaliłem i mam problem, bo na starcie wąż ciągle rośnie. Dopiero po super pokarmie (nie zawsze) ogon rusza i wąż wydłuża się dopiero po zjedzeniu.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się

  • Ostatnio przeglądający   0 użytkowników

    Brak zarejestrowanych użytkowników przeglądających tę stronę.

×
×
  • Dodaj nową pozycję...