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

Podwójny znak po getch()

Ostatnio zmodyfikowano 2021-11-21 19:15
Autor Wiadomość
NHFL
Temat założony przez niniejszego użytkownika
Podwójny znak po getch()
» 2021-11-16 11:06:11
Cześć, mam problem z moim programem. Na moim komputerze działa bez zarzutu(zazwyczaj) ale na innych komputerach podczas wyświetlania znaku na monitorze dostaje zamiast jednego znaku to dwa obok siebie i od tego momentu mój program się zupełnie chrzani wizualnie. Dostaje efekt można powiedzieć podobny do tego z filmu matrix a tego nie chcę. Przeczytałem w sieci że rozwiązaniem problemu może być podwójne getch(); jedno pod drugim albo fflush(stdin); ale to nie rozwiązuje problemu niestety... Także proszę Was o pomoc a jeśli będzie coś jeszcze do poprawy w kodzie to także śmiało możecie pisać.

C/C++
#include <iostream>
#include <conio.h>
#include <windows.h>
#include <process.h>
#include <time.h>
#include <vector>
#include <algorithm>

using namespace std;

int a = 0;
vector < char > vectorOfChars = { }; // protection against drawing same character at the same time on monitor
vector < int > lifes = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79 };
bool endOfTurn = false, endOfGame = false;

void endOperations();
void writeLine();
void initConsole();
void textColor( int );
void gotoxy( int, int );
int pointsCount( int );
int getRandomNumber();
template < typename >
int findIndex( vector < char > &, char );
template < typename >
int findIndex( vector < int >, int );
VOID functionKbhit( LPVOID );
VOID myThread( LPVOID );

int main()
{
   
initConsole();
   
_beginthread( functionKbhit, 0, NULL ); // input data should be in one thread and read in other threads from one source
   
while( 1 )
   
{
       
for( int x = 0; endOfTurn == false; x++ )
       
{
           
_beginthread( myThread, x, NULL );
           
Sleep( 1000 );
       
}
       
if( endOfGame ) return 0;
       
   
}
}

void endOperations()
{
   
int z;
   
pointsCount( 0 ); // nulled point counter
   
gotoxy( 14, 12 );
   
textColor( 15 );
   
cout << "You Lose! Do you want continue? [Y/N]";
   
   
while( endOfTurn )
   
{
       
static int i = 13;
       
z = getch();
       
if( z != 'n' && z != 'N' && z != 'y' && z != 'Y' )
       
{
           
textColor( 15 );
           
gotoxy( 0, ++i );
           
cout << "Give correct character!";
       
}
       
else if( z == 'y' || z == 'Y' )
       
{
           
vectorOfChars.clear(); // needed clear vector otherwise next turn of game will be using previous characters and game will not be able to rand this characters
           
lifes = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79 }; // set again this vector when turn of game is next
           
i = 13;
           
a = 0;
           
endOfTurn = false;
           
system( "cls" );
           
writeLine();
       
}
       
else if( z == 'N' || z == 'n' ) endOfGame = true;
       
   
}
}

void writeLine()
{
   
textColor( 15 );
   
gotoxy( 0, 22 );
   
cout << "________________________________________________________________________________";
}

void initConsole()
{
   
HANDLE hOut;
   
CONSOLE_CURSOR_INFO ConCurInf;
   
hOut = GetStdHandle( STD_OUTPUT_HANDLE );
   
SetConsoleTitle( "Master of keyboard C++ by Priboi" );
   
ConCurInf.dwSize = 10; // cursor size
   
ConCurInf.bVisible = FALSE;
   
SetConsoleCursorInfo( hOut, & ConCurInf );
   
system( "cls" );
   
writeLine();
}

void textColor( int color )
{
   
HANDLE hConsole;
   
hConsole = GetStdHandle( STD_OUTPUT_HANDLE );
   
SetConsoleTextAttribute( hConsole, color ); // color 0 - black  color 15 - white  color 10 - green
}

void gotoxy( int x, int y )
{
   
COORD c;
   
c.X = x;
   
c.Y = y;
   
SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), c );
}



int pointsCount( int zerowanie )
{
   
int static points = 0;
   
if( zerowanie == 0 ) return points = 0;
   
   
return ++points;
}

int getRandomNumber()
{
   
srand( time( NULL ) );
   
return rand();
}


template < typename T1 > // T1 - vector<int> lub vector<char>&
int findIndex( T1 & arr, char item )
{
   
for( auto i = 0; i < arr.size(); ++i )
   
{
       
if( arr[ i ] == item )
           
 return i;
       
   
}
   
return - 1; // if -1 that means the first chars in same column have get down recently and element in vector is deleted that means others chars in same column will not be present in this vector
}


VOID functionKbhit( LPVOID lpVoid )
{
   
while( 1 )
   
{
       
if( endOfTurn == false ) // this if is necessary because without it we have to press 'Y' or 'N' after game many times and now only twice
       
{
           
if( kbhit() )
           
{
               
a = getch(); //fflush(stdin); // needed because without it we get sometimes writeen two characters on screen instead one. We can resolved this problem alsoe with two getch() instead of fflush
               
a = getch();
           
}
        }
    }
}

VOID myThread( LPVOID lpVoid )
{
   
int x, y, h, b;
   
char character, rakieta = 127;
   
   
for( y = 0; y <= 22; y++ )
   
{
       
if( endOfTurn == true ) _endthread(); // one thread execute function endOperations() and in this line we end others threads
       
       
if( y == 0 )
       
{
           
x = rand() * getRandomNumber() % lifes.size(); // get on beginning possible column where char can get down(where never get down before)
           
x = lifes[ x ];
           
b = rand() % 2;
           
b ? character = rand() % 25 + 65
               
: character = rand() % 25 + 97; // draw upper or lower case character
           
while( find( vectorOfChars.begin(), vectorOfChars.end(), character ) != vectorOfChars.end() ) // check is drawed char is already in vector if is draw another. It prevent from get same character on screen at the same time
           
{
               
b ? character = rand() % 25 + 65
                   
: character = rand() % 25 + 97; // draw upper or lower case character
           
}
           
vectorOfChars.push_back( character ); // if not already in vector add this character to vector
       
}
       
gotoxy( x, y );
       
textColor( 15 );
       
cout << character;
       
Sleep( 160 );
       
gotoxy( x, y );
       
textColor( 0 );
       
cout << character;
       
       
if( a == character && y <= 21 )
       
{
           
a = 0; // nulled global variable after match character
           
vectorOfChars.erase( vectorOfChars.begin() + findIndex( vectorOfChars, character ) );
           
textColor( 10 ); // necessary because loop for is ending with black chars and they stay black if we dont change it
           
gotoxy( x, y );
           
cout << character;
           
gotoxy( 0, 24 );
           
textColor( 15 );
           
cout << "Your points: " << pointsCount( 1 );
           
textColor( 0 ); // delete visually char on screen which appears on screen in moment of press correct key
           
gotoxy( x, y );
           
cout << character;
           
           
y++; // this is needed bacause without it when rocket is send the character on screen is hanged for a second
           
for( int h = 21; h >= y; h--, y++ ) // drawing rocket from down of screen
           
{
               
gotoxy( x, h );
               
textColor( 10 );
               
cout << rakieta;
               
gotoxy( x, y ); // drawing keep going get down character and keep going up rocket until they meet
               
cout << character;
               
Sleep( 160 );
               
gotoxy( x, h );
               
textColor( 0 );
               
cout << rakieta;
               
gotoxy( x, y );
               
cout << character;
           
}
           
_endthread();
       
}
       
if( y == 22 )
       
{
           
vectorOfChars.erase( vectorOfChars.begin() + findIndex( vectorOfChars, character ) );
           
if( findIndex( lifes, x ) != - 1 ) lifes.erase( lifes.begin() + findIndex( lifes, x ) ); // needed condition because when many chars get down in one column the first will delete element from vector and we have to do something with rest chars
           
           
if( lifes.size() == 0 )
           
{
               
endOfTurn = true;
               
endOperations();
           
}
        }
    }
}
P-179065
DejaVu
» 2021-11-16 12:53:42
https://cpp0x.pl/kursy/Kurs-C++/Dodatkowe-materialy/Obsluga-klawiatury-za-pomoca-conio-h/320

Przetestuj sobie kod z tego rozdziału. Zobacz jak się zachowuje na wciskanie klawiszy (np. strzałek). Następnie napisz odpowiednią logikę, chociażby na bazie przykładowego kodu z lekcji.
P-179066
NHFL
Temat założony przez niniejszego użytkownika
» 2021-11-16 17:00:25
Dzięki za zainteresowanie ale chyba nie tam kopie gdzie trzeba... Teraz widzę że mam ten sam problem nawet gdy nie wciskam żadnego klawisza z klawiatury więc to nie wina getch() czy kbhit() wydaje mi się że chodzi tutaj o wielowątkowość.
P-179069
DejaVu
» 2021-11-16 17:02:36
Sekcji krytycznych nigdzie nie masz więc małe szanse, że kod działa poprawnie (jeżeli działa poprawnie to tylko przez przypadek).
P-179070
pekfos
» 2021-11-16 19:20:04
C/C++
VOID functionKbhit( LPVOID lpVoid )
{
   
while( 1 )
   
{
       
if( endOfTurn == false ) // this if is necessary because without it we have to press 'Y' or 'N' after game many times and now only twice
       
{
           
if( kbhit() )
           
{
               
a = getch(); //fflush(stdin); // needed because without it we get sometimes writeen two characters on screen instead one. We can resolved this problem alsoe with two getch() instead of fflush
               
a = getch();
           
}
        }
    }
}
kbhit() pozwala przewidzieć czy getch() będzie blokujące, więc nie ma powodu mieć tego w osobnym wątku, zwłaszcza że ten wątek będzie wciągać 100% rdzenia na kręcenie się w tej pętli. Czytaj znaki tam, gdzie je przetwarzasz. Teraz gubisz znaki, jeśli użytkownik poda je za szybko, co nie jest aż tak szybko przy tych wszystkich sleepach. Słabe rozwiązanie w grze mającej ćwiczyć pisanie na klawiaturze.
Co do dwóch getch(), niektóre klawisze będą generować 2 kody, więc nie będziesz mieć poprawnego zachowania po prostu ignorując pierwszy z nich. Powinieneś sprawdzać czy pierwszy kod to 224, tylko wtedy pobierać drugi i przetwarzać go inaczej niż pierwszy kod by nie mieć zachowania na przykład strzałek dla przypadkowych znaków.

Czemu uruchamiasz myThread() też w osobnym wątku? Sleepy w myThread() są razem większe niż te 1000ms po wystartowaniu wątku, więc generujesz wiele instancji naraz, co pewnie jest przyczyną tego "Matriksa". Tu naprawdę nie ma powodu używać wątków, najprościej będzie jeśli z nich zrezygnujesz w tym programie.
P-179071
NHFL
Temat założony przez niniejszego użytkownika
» 2021-11-21 19:15:18
Dzięki pekfos. Dzisiaj przysiadłem nad tym i wszystko wrzuciłem do funkcji i korzystam teraz jedynie z głównego wątku procesu. Teraz działa bez zarzutu.
P-179078
« 1 »
  Strona 1 z 1