Wisielec C++

Bash, C, C++, Java, PHP, Ruby, GTK, Qt i wiele innych - wszystko tutaj.
Roshun
Sędziwy Jeż
Sędziwy Jeż
Posty: 31
Rejestracja: 07 cze 2012, 18:25
Płeć: Mężczyzna
Wersja Ubuntu: 13.10
Środowisko graficzne: Unity
Architektura: x86_64
Lokalizacja: Białystok
Kontakt:

Wisielec C++

Post autor: Roshun »

Witam. Nie jestem jakimś orłem w programowaniu, więc różnie mi to idzie. Ostatnio w szkole zadano nam napisanie gry w C++. Do wyboru było kilka między innymi poczciwy wisielec :) Jednak pojawiło się kilka problemów. Otóż nie wiem z jakiego powodu program się zapętla, w jednym miejscu (prawdopodobnie złe zliczanie zmiennych bądź zły warunek w pętli), oraz nie wiem z jakiego powodu dodaje dodatkowy znak '_'. Jeśli znalazłby się na forum ktoś kto potrafiłby to naprawić, i wytłumaczyć mi gdzie zrobiłem błąd, byłbym bardzo wdzięczny. W kodzie zamieściłem komentarze, aby był chociaż trochę bardziej czytelny :)

Kod: Zaznacz cały

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <cstdlib>
#include <string.h>
using namespace std;
string slowo, podawane;  // 1. słowo z pliku 2. to które będziemy podawać 
void kategoria()  
	{
		int help=0, ktore=1; // 2 zmienne pomocnicze
		char a; // zmienna do menu
		cout<<"Wybierz kategorie:"<<endl<<"1 - INFORMATYKA"<<endl<<"2 - ZWIERZETA"<<endl<<"3 - ROSLINY"<<endl<<"4 - ZIMA"<<endl<<"5 - LATO"<<endl<<"6 - INNE"<<endl<<"(Jesli nie otrzymasz potwierdzenia wybierz jeszcze raz)"<<endl<<"Wybieram kategorie: "<<endl;
		switch(a=getchar())
		{
			case '1':
				cout<<"Wybrales kategorie: INFORMATYKA"<<endl;
				ktore=1;
				break;
			case '2':
				cout<<"Wybrales kategorie: ZWIERZETA"<<endl;
				ktore=2;
				break;
			case '3':
				cout<<"Wybrales kategorie: ROSLINY"<<endl;
				ktore=3;
				break;
			case '4':
				cout<<"Wybrales kategorie: ZIMA"<<endl;
				ktore=4;
				break;
			case '5':
				cout<<"Wybrales kategorie: LATO"<<endl;
				ktore=5;
				break;
			case '6':
				cout<<"Wybrałes kategorie: INNE"<<endl;
				ktore=6;
				break;
			default: 
				help++;
				break;
		}
	if(help==1) {
		system("clear"); 
		kategoria();
		}
			int p; // potem do przerywania czytania wyrazu z pliku losowana przez komputer
			
			if(ktore==1) { ifstream wej("informatyka"); {while(!wej.eof())
				  {
					  wej>>slowo;
					  p=(int)rand()%3;
					  if(p==1) break; 
					}
					  }
					  }
			if(ktore==2) { ifstream wej("zwierzeta"); {while(!wej.eof())
				  {
					  wej>>slowo;
					  p=(int)rand()%3;
					  if(p==1) break; 
					}
					  }}
			if(ktore==3) { ifstream wej("rosliny"); {while(!wej.eof())
				  {
					  wej>>slowo;
					  p=(int)rand()%3;
					  if(p==1) break; 
					}
					  } }
			if(ktore==4) { ifstream wej("zima"); {while(!wej.eof())
				  {
					  wej>>slowo;
					  p=(int)rand()%3;
					  if(p==1) break; 
					}
					  }}
			if(ktore==5) { ifstream wej("lato"); {while(!wej.eof())
				  {
					  wej>>slowo;
					  p=(int)rand()%3;
					  if(p==1) break; 
					}
					  } }
			if(ktore==6) { ifstream wej("inne"); {while(!wej.eof())
				  {
					  wej>>slowo;
					  p=(int)rand()%3;
					  if(p==1) break; 
					}
					  }}
	cout<<slowo<<endl; // dla sprawdzenia poprawnosci przeczytania przez program
	}
void pregame()
{
int b=slowo.size(); 
podawane.clear(); // czyszczenie zawsze bezpieczniej i pewniej
for(int i=0; i<b; i++) podawane=podawane+'_'; // podstawienie pod nieznane litery znaku '_'
}
void game()
{
	int kri; // zmienna zliczająca chybienia
	char znak; // znak podawany
	int b=slowo.size(); // długość słowa juz raz wystąpila ale nie chce zmieniac zeby sie nie pomylic
	while(kri!=6) // warunek dalszej gry
	{
		cout<<podawane<<endl;   // nasz wyraz zastapiony znakami '_'
		cout<<"Podaj znak"<<endl;
		znak=getchar();
		if(slowo.find(znak)==0) { kri++; continue; } // jesli znak nie wystepuje zwiększamy zmienną porażki 
		for(int i=0; i<b; i++) // petla podstawiajaca trafione litery do naszego stringa
		{
		if(slowo[i]==znak) podawane[i]=znak;
		}
	system("clear");
	}	
	if(kri==6) cout<<"PRZEGRALES"<<endl;
}
int main()
{
	srand(time(NULL));
// tu bedzie while - menu glowne
	kategoria();
	pregame();
	game(); 
	return 0;
}
Poza tym pozostaje zrobienie menu ale to już łatwo da się zrobić na switchu.
P.S
Ma ktoś jakiś pomysł rysowania szubienicy?
TrolleY
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 160
Rejestracja: 06 cze 2013, 12:40
Wersja Ubuntu: inny OS
Środowisko graficzne: Inne
Architektura: x86_64

Re: Wisielec C++

Post autor: TrolleY »

Funkcja kategorie() jest delikatnie mówiąc nieczytelna. Masz tam całkowicie zbędną rekurencję (wywołujesz w niej po raz kolejny funkcję kategorie co jest w tym przypadku niepoprawne nawet jeśli działa). Skoro masz już tą zmienną help=0 to powinieneś mieć coś w tym stylu:

Kod: Zaznacz cały

int help=0;
while(help!=1)
{
     twoje switche
     gdy wszystko jest ok to ustawiasz help=1
}
Tak nawiasem tych switchy można też uniknąć i skrócić kod do ok 3 linijek ale byłoby to pewnie dla ciebie mocno nieczytelne więc można to zostawić jak jest.

Zwróciłem uwagę tak na szybko jeszcze na użycie metody find() z klasy string, której używasz przy sprawdzeniu czy litera należy do słowa. Wg reference:
http://www.cplusplus.com/reference/string/string/find/
jak nie znajdzie podnapisu to zwraca string::npos czyli -1 a nie 0.

Powód dla którego wyświetla za dużo '_'? Myślałem, że metoda size() liczy razem ze znakiem końca napisu 0 ale wg reference tak nie jest, więc podejrzewam, że coś źle sczytuje z pliku.
Linux Mint 17 + Cinnamon (x64) / Windows 7 (x64)
Roshun
Sędziwy Jeż
Sędziwy Jeż
Posty: 31
Rejestracja: 07 cze 2012, 18:25
Płeć: Mężczyzna
Wersja Ubuntu: 13.10
Środowisko graficzne: Unity
Architektura: x86_64
Lokalizacja: Białystok
Kontakt:

Re: Wisielec C++

Post autor: Roshun »

Poprawiłem funkcje katergorie(), tak jak pisałeś, zbyt często kombinuje i zapominam o prostych sposobach na rozwiązanie problemu. :) Program zaczął przyjmować pierwszą literę wyrazu, więc jeden problem załatwiony. Wy-edytowałem pliki tekstowe jeszcze raz. Jednak nadal nie zlicza odpowiednio zmiennej odpowiadającej za koniec gry. Zmodyfikowałem warunek, aby porównywało z "-1" jednak nadal nic się nie dzieje.

Kod: Zaznacz cały

void game()
{
	
	int kri; 
	char znak; 
	int b=slowo.size(); 
	while(kri!=6) 
	{
		system("clear");
		cout<<podawane<<endl;   
		cout<<"Podaj znak"<<endl;
		znak=getchar();
		if(slowo.find(znak)==-1)  {kri++; continue;}
		for(int i=0; i<b; i++) 
		{
		if(slowo[i]==znak) podawane[i]=znak;
		}
	system("clear");
	}	
	if(kri==6) cout<<"PRZEGRALES"<<endl;
}

Kompilator zwraca jako uwagę (program się normalnie kompiluje i uruchamia)

Kod: Zaznacz cały

gra.cpp:117:25: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
Linijka z metodą find()

Odnośnie zastąpienia switch'y jakby to wyglądało?
Awatar użytkownika
ethanak
Wygnańcy
Posty: 3054
Rejestracja: 04 gru 2007, 13:19
Płeć: Mężczyzna
Wersja Ubuntu: 12.04
Środowisko graficzne: GNOME
Architektura: x86
Lokalizacja: Bielsko-Biała
Kontakt:

Re: Wisielec C++

Post autor: ethanak »

find jest typu size_t, czyli na mój rozum porównuj z (size_t)-1
przynajmniej tak by było w C. w C++ masz string::npos.
google "c++ string find" i pierwszy wynik...
Кто жопой родился, чижиком не помрёт
Awatar użytkownika
enedil
Przebojowy Jelonek
Przebojowy Jelonek
Posty: 1352
Rejestracja: 08 wrz 2012, 16:54
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: i3
Architektura: x86_64
Kontakt:

Re: Wisielec C++

Post autor: enedil »

npos nie oznacza -1, a największą wartość inta, którą można uzyskać na danym komputerze. Dlatego lepiej, żeby porównanie wyglądało tak:

Kod: Zaznacz cały

slowo.find(znak) == npos
Dobrze jest, psiakrew, a kto powie, że nie, to go w mordę!

~moderatorzy
Awatar użytkownika
ethanak
Wygnańcy
Posty: 3054
Rejestracja: 04 gru 2007, 13:19
Płeć: Mężczyzna
Wersja Ubuntu: 12.04
Środowisko graficzne: GNOME
Architektura: x86
Lokalizacja: Bielsko-Biała
Kontakt:

Re: Wisielec C++

Post autor: ethanak »

a co oznacza twoim zdaniem (size_t)-1
Кто жопой родился, чижиком не помрёт
Roshun
Sędziwy Jeż
Sędziwy Jeż
Posty: 31
Rejestracja: 07 cze 2012, 18:25
Płeć: Mężczyzna
Wersja Ubuntu: 13.10
Środowisko graficzne: Unity
Architektura: x86_64
Lokalizacja: Białystok
Kontakt:

Re: Wisielec C++

Post autor: Roshun »

W obu przypadkach, nic się nie dzieje. Istnieje może jakiś inny sposób, sprawdzenia czy w wyrazie występuje dany znak?
Awatar użytkownika
ethanak
Wygnańcy
Posty: 3054
Rejestracja: 04 gru 2007, 13:19
Płeć: Mężczyzna
Wersja Ubuntu: 12.04
Środowisko graficzne: GNOME
Architektura: x86
Lokalizacja: Bielsko-Biała
Kontakt:

Re: Wisielec C++

Post autor: ethanak »

w c jest funkcja strchr - może spróbujesz? zwraca wskaźnik albo NULL czyli może być bezpośrednio użyta w ifie.
Кто жопой родился, чижиком не помрёт
Roshun
Sędziwy Jeż
Sędziwy Jeż
Posty: 31
Rejestracja: 07 cze 2012, 18:25
Płeć: Mężczyzna
Wersja Ubuntu: 13.10
Środowisko graficzne: Unity
Architektura: x86_64
Lokalizacja: Białystok
Kontakt:

Re: Wisielec C++

Post autor: Roshun »

Coś nie wychodzi mi sklejenie tej funkcji do kupy. Zastanawiam się czy coś takiego miałoby sens, sam sposób:

Kod: Zaznacz cały

void game()
{
	int kri=0; // po poprawce
	char znak; 
	int b=slowo.size(); 
	while(kri!=6) 
	{
		int help=0;
		system("clear");
		cout<<podawane<<endl;   
		cout<<"Podaj znak"<<endl;
		znak=getchar();
		for(int i=0; i<b; i++) 
		{
		if(slowo[i]==znak) {
			podawane[i]=znak;
			help++;
		}
		}
		if(help==0) kri++;
	system("clear");
	}	
	if(kri==6) cout<<"PRZEGRALES"<<endl;
}
EDIT
Heh błąd młodego "programisty" brak wyzerowania kri przy deklaracji. Teraz problem wygląda tak że po 3 złych próbach wychodzi z while, o trzy próby za wcześnie.
Ostatnio zmieniony 31 sty 2014, 14:08 przez Roshun, łącznie zmieniany 3 razy.
Awatar użytkownika
ethanak
Wygnańcy
Posty: 3054
Rejestracja: 04 gru 2007, 13:19
Płeć: Mężczyzna
Wersja Ubuntu: 12.04
Środowisko graficzne: GNOME
Architektura: x86
Lokalizacja: Bielsko-Biała
Kontakt:

Re: Wisielec C++

Post autor: ethanak »

a może byś zainicjalizował kri?
Кто жопой родился, чижиком не помрёт
Awatar użytkownika
enedil
Przebojowy Jelonek
Przebojowy Jelonek
Posty: 1352
Rejestracja: 08 wrz 2012, 16:54
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: i3
Architektura: x86_64
Kontakt:

Re: Wisielec C++

Post autor: enedil »

Po co dajesz system("clear")?
Dobrze jest, psiakrew, a kto powie, że nie, to go w mordę!

~moderatorzy
Awatar użytkownika
ethanak
Wygnańcy
Posty: 3054
Rejestracja: 04 gru 2007, 13:19
Płeć: Mężczyzna
Wersja Ubuntu: 12.04
Środowisko graficzne: GNOME
Architektura: x86
Lokalizacja: Bielsko-Biała
Kontakt:

Re: Wisielec C++

Post autor: ethanak »

znajdź natywny zamiennik, a jak znajdziesz to już będziesz wiedział po co.
Кто жопой родился, чижиком не помрёт
Awatar użytkownika
Nettmanek
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 167
Rejestracja: 26 lis 2008, 18:51
Płeć: Mężczyzna
Wersja Ubuntu: 14.04
Środowisko graficzne: Unity
Architektura: x86_64
Lokalizacja: Wolverhampton
Kontakt:

Re: Wisielec C++

Post autor: Nettmanek »

możnaby zamienic string'a na chara i sprawdzac znak po znaku... chociaż wydaje mi się, że w stringu też to jest możliwe.
Lenovo G580-20150 | Intel Core i3 3120M | 8GB DD3 | Intel HD 4000 & Nvidia GF 710M | 1TB HDD | kubuntu 13.10 64bit
Awatar użytkownika
ethanak
Wygnańcy
Posty: 3054
Rejestracja: 04 gru 2007, 13:19
Płeć: Mężczyzna
Wersja Ubuntu: 12.04
Środowisko graficzne: GNOME
Architektura: x86
Lokalizacja: Bielsko-Biała
Kontakt:

Re: Wisielec C++

Post autor: ethanak »

na char* a nie na chara jak mniemam?
poza tym to ma być c++, a nie c++ wywołujący funkcje w ansi c.
Кто жопой родился, чижиком не помрёт
Roshun
Sędziwy Jeż
Sędziwy Jeż
Posty: 31
Rejestracja: 07 cze 2012, 18:25
Płeć: Mężczyzna
Wersja Ubuntu: 13.10
Środowisko graficzne: Unity
Architektura: x86_64
Lokalizacja: Białystok
Kontakt:

Re: Wisielec C++

Post autor: Roshun »

Trochę odświeżam temat. Dzięki pomocy mojego nauczyciela udało się trochę poprawić kod. Działa już dobrze zlicza wszystkie zmienne w odpowiedni sposób. Należało w kilku miejscach dostawić linijkę

Kod: Zaznacz cały

cin.ignore();
Teraz pytanie do Was macie pomysły, aby uatrakcyjnić grę. Jakieś takie proste efekty. W najbliższym czasie dodam jeszcze rysowanie wisielca i ogólnie czyszczenie ekranu, aby całość była bardziej przejrzysta.

Kod: Zaznacz cały

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <cstdlib>
#include <string.h>
using namespace std;
string slowo, podawane;  
void kategoria()  
	{
		int help=0, ktore=1; 
		char a; 
		while(help!=1)
		{
		cout<<"Wybierz kategorie:"<<endl<<"1 - INFORMATYKA"<<endl<<"2 - ZWIERZETA"<<endl<<"3 - ROSLINY"<<endl<<"4 - ZIMA"<<endl<<"5 - LATO"<<endl<<"6 - INNE"<<endl<<"Wybieram kategorie: "<<endl;
		switch(a=getchar())
		{
			case '1':
				cout<<"Wybrales kategorie: INFORMATYKA"<<endl;
				ktore=1;
				help++;
				break;
			case '2':
				cout<<"Wybrales kategorie: ZWIERZETA"<<endl;
				ktore=2;
				help++;
				break;
			case '3':
				cout<<"Wybrales kategorie: ROSLINY"<<endl;
				ktore=3;
				help++;
				break;
			case '4':
				cout<<"Wybrales kategorie: ZIMA"<<endl;
				ktore=4;
				help++;
				break;
			case '5':
				cout<<"Wybrales kategorie: LATO"<<endl;
				ktore=5;
				help++;
				break;
			case '6':
				cout<<"Wybrałes kategorie: INNE"<<endl;
				ktore=6;
				help++;
				break;
			default: 
				system("clear");
				break;
		}
		}
		cin.ignore(); 
			int p; 
			
			if(ktore==1) { ifstream wej("informatyka"); {while(!wej.eof())
				  {
					  wej>>slowo;
					  p=(int)rand()%3;
					  if(p==1) break; 
					}
					  }
					  }
			if(ktore==2) { ifstream wej("zwierzeta"); {while(!wej.eof())
				  {
					  wej>>slowo;
					  p=(int)rand()%3;
					  if(p==1) break; 
					}
					  }}
			if(ktore==3) { ifstream wej("rosliny"); {while(!wej.eof())
				  {
					  wej>>slowo;
					  p=(int)rand()%3;
					  if(p==1) break; 
					}
					  } }
			if(ktore==4) { ifstream wej("zima"); {while(!wej.eof())
				  {
					  wej>>slowo;
					  p=(int)rand()%3;
					  if(p==1) break; 
					}
					  }}
			if(ktore==5) { ifstream wej("lato"); {while(!wej.eof())
				  {
					  wej>>slowo;
					  p=(int)rand()%3;
					  if(p==1) break; 
					}
					  } }
			if(ktore==6) { ifstream wej("inne"); {while(!wej.eof())
				  {
					  wej>>slowo;
					  p=(int)rand()%3;
					  if(p==1) break; 
					}
					  }}
	cout<<slowo<<endl; 
	}
void pregame() 
{
int b=slowo.size(); 
podawane.clear(); 
for(int i=0; i<b; i++) podawane=podawane+'_'; 
}
void game()
{
	
	int kri=0, b=slowo.size(); 
	char znak;
	while(kri!=5)
	{
		cout<<podawane<<endl;
		znak=getchar();
	
		cout<<"Podany znak: "<<znak<<endl;
		if(slowo.find(znak)!=string::npos) 
		{
            cin.ignore();                               
			for(int i=0; i<b; i++)
			{
				if(znak==slowo[i]) podawane[i]=znak;
			}
		}
		
		if(slowo.find(znak)==string::npos) {kri++; cin.ignore();}
		if(slowo==podawane) { cout<<slowo<<endl<<"WYGRALES"<<endl; break; }
		
	}
	if(kri==5) cout<<"PRZEGRALES"<<endl<<"Slowo ktore bylo rozwiazaniem to: "<<slowo<<endl;
	cout<<"Wcisnij ENTER, aby wrócić do menu."<<endl;
	getchar();
}
int main()
{
	int cos=0;
	char help;
	srand(time(NULL));
	// co kto dlaczego
	while(cos!=1)
	{
		cout<<"Wcisnij: "<<endl<<"1 - Gra"<<endl<<"2 - Zasady"<<endl<<"3 - Zakoncz"<<endl;
		switch(help=getchar())
		{
			case '1':
				system("clear");
				kategoria();
				pregame();
				game();
				break;
			case '2':
				system("clear");
				cout<<"Prosta gra. Musisz odgadnąć hasło wpisując litery."<<endl<<"Możesz podać po jednej lub wpisać cały wyraz."<<endl<<"W grze występują podwójne słowa. W tym przypadku zamiast spacji wpisz '-' (minus)"<<endl;
				cout<<"Zrozumiono?"<<endl<<"Wciśnij ENTER, aby przejsc do menu."<<endl;
				cin.ignore();
				getchar();
				system("clear");
				break;
			case '3':
				cos++;
				break;
		}
	} 
	return 0;
}
ODPOWIEDZ

Wróć do „Programowanie”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 11 gości