[pomoc] Pisanie w konsoli - Alternatywa dla cout

0

Chciałem się zapytać czy w C++ istnieje jakaś alternatywa dla cout (inny sposób pisania w konsoli). Programuje tetris w konsoli ( ;-P wiem że to śmiesznie brzmi, ale mowie prawdę) i zależy mi na szybkim pisaniu (przy każdym działaniu muszę na nowo "renderować" cały obraz), dlatego zależy mi na szybszym niż cout sposobie. Podajcie każdy sposób jaki znacie (o ile są w ogóle jakieś inne), a ja już sobie sprawdzę czy jest szybszy czy nie :-D</ort>

0

Szybszy od cout jest printf, ale nie tędy droga.
Rozumiem że piszesz "pełnoekranowy program konsolowy". To znaczy że nie powinieneś kasować całego ekranu za każdym razem, a jedynie to co trzeba: czyli kasować klocka w poprzednim położeniu i rysować go w nowym.
Do tego potrzebujesz funkcji WinAPI do obsługi konsoli, albo jakiejś gotowej biblioteki np. ncurses.

0

Według mnie szybkość iostreama wystarcza, dopisz jeszcze na poszątku ios_base::sync_with_stdio(0). Jak będziesz cały ekran odświeżał kilkadziesiąt razy na sekunde to nie powinno być problemów.

0

co do ios_base::sync_with_stdio(0) to jest szybszy, ale modyfikuje mi trochę tę plansze (za szybko rysuje niektóre elementy), no i tak jest za wolny. Co do printf to jest szybszy, ale i tak za wolny :D. Teraz tylko zostało mi to WinAPI. Dzięki za szybką odpowiedź (w ogóle ten topic jakiś taki "szybki" :-D). Azarien napisałeś "pełnoekranowy"- o to właśnie mi chodzi, ale nie wiem jak zrobić by konsola była na starcie programu w trybie pełnoekranowym. Możesz powiedzieć jak to osiągnąć?

0

@yubasek:
To, co powiedział @Azarien, to prawidłowe rozwiązanie. Ale tak gwoli ścisłości, to myślę, że gdy chcesz wyświetlić zwykłe ciągi znaków, to najszybsze może się okazać coś w rodzaju funkcji pusts z stdio.h. Ona robi tylko tyle: wypisuje stringa (i dodaje znak nowej linii). Nie ma tylu bajerów co cout, nie parsuje też ciągu z formatem jak printf. Ewentualnie możesz spróbować fwrite przekierowanego na stdout, czy czegoś podobnego.

Ale jeśli robisz wypisywanie na ekran, potem clrscr i znowu wypisywanie na ekran (i tak w kółko), to chyba nic tu nie pomoże. Problemem jest to, że masz naprzemiennie jedną klatkę tetrisa i jedną pustego, czarnego ekranu (z powodu clrscr). To najgorszy sposób z możliwych. Jeśli z niego korzystasz, to może się okazać, że nie musisz się uciekać do przerysowywania fragmentów ekranu. Wystarczy narysować cały ekran, ale zaczynając od lewego górnego roku. Tj. mażąc po tym, co było poprzednio. Sam brak clrscr sprawi, że będzie to wyglądało milion razy lepiej.

0

Masz w 100% racje i wiem, że moje rozwiązanie to najgorsze z możliwych. Ja robię to w ten sposób, ponieważ chciałem by było to proste rozwiązanie na ogólnodostępnych funkcjach na poziomie technikum :D (zresztą sam nie mam zbyt wielkiej wiedzy i ciężko mi tak w 5 min ogarnąć np tę bibliotekę ncurses). Próbuje to jak najlepiej zoptymalizować by aż tak strasznie nie raziło w oczy :D. Zdaję sobie sprawę, że mruganie konsoli to rzecz nieunikniona jednak chcę zrobić taką prostą wersje, a później zajmę się ogarnianiem tych bibliotek :). Zobacze co z tym pusts się uda zrobić, choć jest tak okrojone, ponieważ nie tylko wyrzucam na okno konsoli stringi, ale także zmienne i chary w postaci liczbowej.

0

@yubasek:
Czyli robisz to tak, że na zmianę czyścisz ekran (clrscr) i wszystko na nim rysujesz?

To wbrew pozorom dobra wiadomość dla Ciebie. Skoro to chodzi wolno, to nic dziwnego. Jest bardzo duża szansa, że nie będziesz musiał kombinować z odmalowywaniem tylko fragmentów ekranu (choć takie kombinowanie na pewno mogłoby Ci dać trochę satysfakcji; podobnie jest to zrobione np. w kodzie zarządzającym okienkami w systemie operacyjnym).

Wystarczy, że wyczaisz jak po każdym narysowaniu całej planszy cofnąć kursor do punktu wyjścia. Jeśli będziesz tak robił, nawet "naiwnie" rysując za każdym razem całą planszę, to IMO masz sporą szansę, że to w zupełności wystarczy.

W ogóle to jestem dość głupi, że nie wpadłem wcześniej na jedną rzecz. Taki rodzaj buforowania. Spróbuj nie wywoływać couta dla każdej linijki i dla każdej operacji. Zamiast ładować wszystko w ten sposób na ekran, ładuj to do... stringa jakiegoś. Albo std::stringa, albo nawet zwykłego c-stringa (char*), bo przecież rozmiar ekranu masz stały. Możesz pomnożyć sobie wysokość i szerokość ekranu, dodać 1 na znak końca stringa i zaalokować tyle właśnie pamięci. I przy każdej klatce najpierw załadować wszystko do tego bufora (nie na ekran), a dopiero na końcu klatki zrobić jedną operację cout lub puts, zrzucając za jednym zamachem cały bufor.

Aby "drukować" do bufora zamiast na ekran użyj np. sprintf lub strumieni stringowych z C++.

Takie coś może czasem dać SPORE przyspieszenie. Czasem realne, gdy każde drukowanie na ekranie jest drogie, a czasem tylko subiektywne. Dzięki temu nie będzie widać, jak ekran jest rysowany stopniowo, tylko całość planszy pojawi się na nim natychmiast.

0

a ja polece ci coś takiego

w tetrisie nie musisz mieć fps 30 tylko np 5-6 przecież to nie jest płynna animacja ruchu kostki może ona przeskakiwać co 0,2 cm (przykład) więc rób tak

funkcja rysuj
sleep(1000)//przykład
czyść
funkcja rysuj
sleep(1000)//przykład
czyść
funkcja rysuj
sleep(1000)//przykład
czyść
i tak dalej chyba dobre rozwiązanie?

0

Pod warunkiem, że gracz nie będzie naciskał klawiszy to tak...

0

Mam tak jak mówicie [system("cls") i rysujplansze()]. Wszystko zoptymalizowałem tak, że ekran nigdy nie jest odświerzany bez sensu tylko wtedy gdy coś się "ruszy". Najpierw rysowane jest takie jakby logo "TETRIS" (naokoło taka ramka z tekstu). Następnie z tablicy 2wymiarowej ładowana jest plansza na ekran(oczywiście z ramką dookoła). Wszystko trwa ułamek sekundy, ale jeśli ruszam klockami za pomocą klawiszy to wygląda to troszkę jak by się części klocka ciągnęły za sobą( najpierw przeskoczy jedna część potem następna, aż w końcu cały klocek zostanie przesunięty). Trwa to co prawda ułamek, no ale widać to "ciągnięcie się" no i mrugnięcie ekranu. Co do tego by wszystko załadować do jednego stringa to jest dobry pomysł(chociaż kod już raczej nie będzie zbyt czytelny ale ważne żeby szybko działało). Powiedzcie mi tylko jak do stringa wrzucić "entery" i jakim operatorem łączy się ciągi znaków w C++ :D. Ach i jeszcze bym zapomniał bo ja tam jeszcze dorzucam chary w formacie liczbowym [cout<<(char) 216]- czy to też będzie można do stringa wstawić ?:D

0

printf i cout to w zasadzie to samo. To jest strumień danych do standardowego wyjścia, które może być ekranem, plikiem, portem drukarki lub czarną dziurą.
Prawda jest taka, że ty powinieneś ominąć system operacyjny. (lub przynajmniej standardowe wyjście-wejście). Byłą kiedyś taka biblioteka conio (jeśli dobrze pamiętam).
Tam były funkcje cprintf, kbhit, getch które służyły do pisania/czytania bezpośrednio na konsoli. W zasadzie to jest to co jest ci potrzebne.
Wada jest taka, że biblioteka ta nie jest częścią standardu.

0

akurat z kbhit i getch korzystam by sczytać klawisze kierowania klockiem z klawiatury. Zrobiłem tak, że wszystko władowałem do std::string i wyświetliłem za pomocom cout. Efekt widać od razu, bo działa o wiele szybciej, ale jeszcze się troszkę ciągnie. Chciałbym wyświetlić to za pomocą puts() by było najszybciej jak to tylko możliwe :D, problem w tym, że nie chce przyjąć ode mnie std::stringa. Próbowałem rzutowania w stylu: (char) zmienna, ale nie pomogło. Powiedzcie mi jak wyświetlić za pomocą puts() zmienną typu std::string

0

@yubasek:
std::string ma metodę c_str(), która zwraca stary dobry string znany z C, używany przez puts i inne tego typu funkcje:

puts( moj_std_string.c_str() );

Wątpię jednak, by zmiana jednej operacji z cout na puts cokolwiek dała. Jeśli masz przeskakiwanie, to prawdopodobnie wina tego clrscr().

0
yubasek napisał(a)

nie wiem jak zrobić by konsola była na starcie programu w trybie pełnoekranowym. Możesz powiedzieć jak to osiągnąć?
Przez „pełnoekranowy” miałem na myśli, że twój program zajmuje całe okno konsoli, udając jakąś tam grafikę, a nie wypisuje po prostu ciurkiem tekstu.
A jeśli chodzi o tryb pełno-pełnoekranowy, jak pod DOS-em to bywało, można go aktywować za pomocą SetForegroundWindow na oknie konsoli, a następnie ShowWindow z SW_MAXIMIZE.
Niestety, o ile w Win9x praktycznie zawsze a w WinXP zazwyczaj tryb pełnoekranowy działał, to od Visty począwszy na większości komputerów nie działa wcale: próba przełączenia np. konsoli za pomocą alt-enter kończy się komunikatem że tryb pełnoekranowy jest niedostępny.
Jest to wina bezpośrednio nowych sterowników grafiki które nie obsługują trybu tekstowego.

0

@MarekR22 [conio.h]

Wada jest taka, że biblioteka ta nie jest częścią standardu.

Ale rozwiązuje w prosty sposób problemy poruszone w wątku i jest łatwa w użyciu.
(conio Borlanda)

Tam były funkcje cprintf, kbhit, getch

i kilka innych bardzo przydatnych np. gettext ,puttext,window
pozwalające na 'blokowe' wstawianie i kopiowanie znaków na konsoli (bufor?),wydzielanie 'okien'
dla tekstu ..
Moim zdaniem mordowanie się ze standardem akurat przy takim programie nie jest wskazane
bo efekt będzie mizerny.
Przykład z conio (Borland)

#include <conio.h>
#include <stdio.h>
const int STRZALKA_LEWO  =  75 ;
const int STRZALKA_PRAWO =  77 ;
const int STRZALKA_GORA  =  72 ;
const int STRZALKA_DOL   =  80 ;
const int Esc = 27 ;
int pozycja_x ;     // 1 - 80
int pozycja_y ;     // 1 - 25
char klocek[]={245,0x33};
char tlo[2];

//--------------------------------------------------------------------
void FunStrzalkowa(int wybor )
{
                 switch(wybor)
              {
                 case STRZALKA_GORA:
                 puttext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,tlo);
                   pozycja_y-- ;
                 puttext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,klocek);
                 break;

                 case STRZALKA_LEWO:
                 puttext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,tlo);
                   pozycja_x-- ;
                 puttext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,klocek);
                 break;

                 case STRZALKA_PRAWO:
                 puttext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,tlo);
                   pozycja_x++ ;
                 puttext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,klocek);
                 break;

                 case STRZALKA_DOL:
                 puttext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,tlo);
                   pozycja_y++ ;
                 puttext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,klocek);
                 break;

                 default: ;
               }

}
//---------------------------------------------------------------------------
int main(int argc, char **argv)
{
  int wybor ;

   clrscr();
   pozycja_x = 10;     // klocek na pozycji 10,10
   pozycja_y = 10;
   // stawiamy klocka :-)
   gettext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,tlo);// pobranie tła
   puttext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,klocek);//wstawienie
  while(1)
  {
        if(kbhit())
       {
            wybor = getch(); // automatycznie pobiera znak po kbhit

           if(wybor == Esc)
           {
             break;
           }

            if(wybor == 0||wybor ==224)     // nacisnieci klawiszy funkcyjnych powoduje wpisanie
            {                          // do bufora klaw . 2 znakow
                wybor = getch();   // wyjecie drugiego
                FunStrzalkowa(wybor);
            }
        }

  }
        getch();
        return 0;
}

To oczywiście makaron ala C ale po przerobieniu klocka na klasę nabierze wyglądu...
Klocek śmiga i nawet nie mrugnie ;-) .
Przy użyciu conio2 np. dla Dev C++ potrzebne są drobne zmiany

0

Właśnie używam deva i powyższy przykład coś niezbyt mi działa. Spróbuje go przerobić.

0

Trzeba pobrać pakiet (jeśli nie jest zainstalowany) z biblioteką conio2
bo 'standardowe' conio Dev nie zawiera fun gettext puttext
Funkcje te mają też różne prototypy w stosunku do tych z Borlanda a więc
trzeba zamienić zmienne przechowujące informacje o znaku :
dodać #include <conio2.h>

char klocek[]={245,0x33};
char tlo[2];

zmienić na:

char_info klocek={245,0x33};
char_info tlo;

i następnie , wszystkie wystąpienia funkcji z :

gettext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,tlo);// pobranie tła

na :

gettext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,&tlo);

oraz :

puttext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,tlo);
......
puttext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,klocek);//wstawienie

na:

puttext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,&tlo);
....
puttext(pozycja_x,pozycja_y,pozycja_x,pozycja_y,&klocek);

a i dolinkować (dodać w opcjach linkera ) bibliotekę statyczną dla conio2...

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