Shebang.pl

Rozdział 10. Projekt praktyczny: tajemnicze słowo

Czytając ten kurs od początku poznałeś wiele nowych pojęć, takich jak kompilator, środowisko programistyczne, zmienna, funkcja, instrukcja warunkowa, pętla itd. W toku nauki obejrzałeś wiele przykładów użycia opisywanych konstrukcji językowych, ale dotychczas nie miałeś jeszcze okazji napisać własnego większego programu, aby przećwiczyć swoje umiejętności. Czas to zmienić. W tym rozdziale napiszesz swój pierwszy prawdziwy program.

Jaki jest cel wykonania takiego praktycznego projektu? Abyś użył zdobytej wiedzy w praktyce i dzięki temu lepiej utrwalił, a także rozwinął swoje umiejętności. Najlepszym sposobem na naukę programowania jest wykonywanie praktycznych zadań.

Temat tego projektu nie jest bardzo skomplikowany, ale za to zabawny. Napiszemy grę, która będzie mieszała litery w słowach i zadaniem gracza będzie odgadnąć, o jakie słowo chodzi.

Rysunek 10.1. Uruchomiona gra w zgadywanie słów

10.1. Zasady gry i wskazówki

Gra, którą napiszemy będzie wymagała odgadnięcia słowa, w którym zostały poprzestawiane litery. Na pierwszy rzut oka może się wydawać, że ten program jest łatwy do realizacji, ale będzie to od nas wymagało wykorzystania wielu konstrukcji i technik poznanych w poprzednich rozdziałach:

Zanim przejdziesz dalej możesz jeszcze raz przeczytać odpowiednie rozdziały, aby odświeżyć sobie wiadomości.

10.1.1. Zasady gry

Zasady naszej gry są następujące:

  1. Pierwszy gracz wpisuje słowo za pomocą klawiatury.
  2. Komputer miesza litery we wpisanym słowie.
  3. Drugi gracz próbuje odgadnąć, jakie słowo wpisał pierwszy gracz.

Oto przykładowa rozgrywka w tę grę:

Wpisz słowo TAJEMNICA Co to za słowo? ATMJNCAIE ACINMEJAT Źle! Co to za słowo? ATMJNCAIE MAJETNICA Źle! Co to za słowo? ATMJNCAIE TAJEMNICA Brawo!
  1. Pierwszy gracz wpisał słowo „TAJEMNICA”.
  2. Komputer pomieszał litery tego słowa i poprosił drugiego gracza o odgadnięcie co to za słowo wyświetlając ciąg „ATMJNCAIE”.
  3. Drugi gracz próbuje odgadnąć oryginalne słowo. Próbuje trzy razy. Pierwsze dwie próby są niepoprawne, o czym zostaje poinformowany. Za trzecim razem w końcu trafia i otrzymuje pochwałę.

Oczywiście drugi gracz może bez problemu przeczytać, jakie słowo wpisał jego rywal. Poszukamy rozwiązania tej usterki pod koniec tego rozdziału.

10.1.2. Wskazówki

Gdy początkującego programistę rzuci się na głęboką wodę i każe mu się napisać realny program, to zazwyczaj kończy się to w ten sam sposób: na pytaniach typu „Od czego zacząć?”, „Jakich narzędzi użyć?”. Krótko mówiąc osoba taka zwykle nie wie, za co się wziąć na początku. To normalne.

Nie chcę jednak, abyś czuł się zagubiony i dlatego dam Ci kilka wskazówek na dobry początek. Pamiętaj jednak, że są to tylko podpowiedzi i możesz z nimi zrobić, co chcesz.

Podziel program na etapy

W omawianym programie można wyróżnić trzy etapy:

  1. Wpisanie słowa do odgadnięcia
  2. Pomieszanie liter
  3. Powtórzenie powyższych czynności w pętli, jeśli nie zostało wpisane odpowiednie słowo

Każdy z tych etapów jest faktycznie niezależny od pozostałych. Skoro tak, to czemu by nie podzielić budowy tego programu właśnie na te trzy osobne części?

  1. Etap pierwszy jest najprostszy: użytkownik musi wpisać słowo, które program musi zapisać w pamięci w postaci łańcucha. Jeśli sprawnie posługujesz się instrukcjami cin i cout, to ten etap nie sprawi Ci żadnych problemów.
  2. Etap drugi jest najbardziej skomplikowany ze wszystkich: mamy łańcuch zawierający słowo, np. „TAJEMNICA”, i chcemy losowo pomieszać jego litery, aby otrzymać ciąg typu np. „ATMJNCAIE”. Jak to zrobić? Będziesz musiał skorzystać z mojej małej pomocy, ponieważ do tego potrzebne jest pewne narzędzie, o którym jeszcze nie było mowy.
  3. Etap trzeci ma podobny poziom skomplikowania, co drugi: trzeba napisać pętlę proszącą gracza o wpisanie typowanego słowa i porównującą te wpisane słowo z oryginałem. Wyjście z pętli następuje, gdy słowo wpisane przez zgadującego jest identyczne z pierwotnym słowem.

Opracuj podstawową strukturę programu wg wyznaczonych etapów

Jak wiesz, każdy program zawiera funkcję main(). Napisz w niej komentarze oddzielające od siebie poszczególne części budowy programu, np.:

int main()
{
    // 1: Pobranie słowa od gracza

    // 2: Wymieszanie liter

    // 3: Poproszenie drugiego gracza o odgadnięcie słowa

    return 0;
}

Czas wziąć się do pracy! Aby ją sobie ułatwić, najlepiej będzie gdy zaczniesz od etapu 1., następnie zrobisz 3., a 2. zostawisz sobie na koniec.

Po wykonaniu etapów 1. i 3. program będzie prosił o podanie słowa, po czym będziesz mógł je wpisać jeszcze raz. Na razie nie będzie to pasjonująca gra, ale przynajmniej dowiesz się czy napisany kod działa poprawnie. Nie ma nic złego w rozwijaniu programu kawałek po kawałku.

Poniżej znajduje się wynik działania wczesnej wersji programu, która na razie ma zaimplementowane tylko etapy 1. i 3.:

Wpisz słowo TAJEMNICA Co to za słowo? ATMJNCAIE Źle! Co to za słowo? MAJETNICA Źle! Co to za słowo? TAJEMNICA Brawo!

W tym stanie program nie wyświetla słowa z pomieszanymi literami, ale i tak w tym miejscu już połowa pracy będzie za Tobą.

10.1.3. Pomoc dotycząca mieszania liter

Etap związany z mieszaniem liter jest najtrudniejszy. Poniżej znajduje się kilka podpowiedzi, dzięki którym poradzisz sobie bez trudu także i z tym problemem.

Generowanie liczb losowych

Aby losowo pomieszać litery w słowie, trzeba wygenerować losową liczbę. Jeszcze nie pokazywałem jak się to robi, a więc poniżej zamieszczam szczegółowe objaśnienie.

Poniżej znajduje się przykładowy program generujący liczby losowe z przedziału od 0 do 4:

#include <iostream>
#include <ctime> // Dołączyć obowiązkowo
#include <cstdlib> // Dołączyć obowiązkowo

using namespace std;

int main()
{
    int lbLosowa(0);

    srand(time(0));

    lbLosowa = rand() % 5;

    return 0;
}

Wylosuj literę

Powyżej pokazałem, jak wylosować liczbę, ale przecież w programie mamy przecież mieszać litery, a nie liczby. Wyobraź sobie, że masz łańcuch znaków o nazwie sekretneSlowo. Wiesz, że łańcuchy można traktować jak tablice znaków, a więc sekretneSlowo[0] odpowiada pierwszej literze, sekretneSlowo[1] — drugiej itd.

Aby zatem wylosować literę, wystarczy tylko wylosować liczbę z przedziału od 0 do liczby znaków we wpisanym przez gracza słowie (którą można sprawdzić przy użyciu instrukcji sekretneSlowo.size()). Oto odpowiedni przykład kodu:

#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>

using namespace std;

int main()
{
    string sekretneSlowo("TAJEMNICA");


    srand(time(0));

    int pozycja = rand() % sekretneSlowo.size();

    cout << "Wylosowana litera:" << sekretneSlowo[pozycja];

    return 0;
}

Usuwanie liter z łańcucha

Aby uniknąć wielokrotnego wylosowania tej samej litery, należy każdą wylosowaną literę od razu usuwać. W tym celu należy użyć funkcji erase():

sekretneSlowo.erase(4, 1); // Usunięcie 5. litery

Funkcja erase() przyjmuje dwa parametry wywołania:

Napisz funkcje

Nie jest to obowiązkowe, ale zamiast umieszczać wszystko w funkcji main() lepiej jest utworzyć kilka funkcji, z których każda będzie wykonywać swoje ściśle określone zadanie. Na przykład cały etap 2., w którym mieszane są litery wpisanego przez gracza słowa doskonale nadaje się do ujęcia w funkcję.

Później funkcję tę będzie można wywołać w funkcji main() w następujący sposób:

pomieszaneSlowo = mieszajLitery(sekretneSlowo);

Do funkcji przekazujemy sekretne słowa, a ona zwraca słowo z poprzestawianymi literami. Pozostało jeszcze tylko napisać kod tej funkcji. Zatem do dzieła!

10.2. Rozwiązanie zadania

Na pewno sporo czasu zajęło Ci zastanawianie się, jak napisać ten program. Często jest tak, że zadanie jest dość trudne i nie od razu wiadomo jak sobie z nim poradzić. Ale nie przejmuj się. Najważniejsze jest próbować. Tylko w ten sposób można robić postępy!

Etapy 1. i 3. są łatwe dla każdego. Jedynie etap 2. wymagał nieco zastanowienia i dlatego zaimplementowałem go w formie funkcji o nazwie mieszajLitery(), aby go później dokładniej omówić.

10.2.1. Kompletny kod źródłowy programu

#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>

using namespace std;

string mieszajLitery(string slowo)
{
	string mieszanka;
	int pozycja(0);

	// Pętla kontynuuje, aż wydobędzie wszystkie litery ze słowa
	while (slowo.size() != 0)
	{
		// Losujemy numer litery
		pozycja = rand() % slowo.size();
		// Dodajemy literę do mieszanki
		mieszanka += slowo[pozycja];
		// Usuwamy wylosowaną literę, aby nie została wylosowana ponownie
		slowo.erase(pozycja, 1);
	}

	// Zwracamy pomieszane słowo
	return mieszanka;
}

int main()
{
	string sekretneSlowo, pomieszaneSlowo, slowoUzytkownika;

	// Inicjacja generatora liczb losowych
	srand(time(0));


	// 1: prosimy użytkownika o wpisanie słowa
	cout << "Wpisz słowo" << endl;
	cin >> sekretneSlowo;

	// 2: mieszamy litery wpisanego słowa i wynik zapisujemy w zmiennej pomieszaneSlowo
	pomieszaneSlowo = mieszajLitery(sekretneSlowo);

	// 3: prosimy użytkownika, aby spróbował odgadnąć słowo
	do
	{
		cout << endl << "Co to za słowo? " << pomieszaneSlowo << endl;
		cin >> slowoUzytkownika;

		if (slowoUzytkownika == sekretneSlowo)
		{
			cout << "Brawo !" << endl;
		}
		else
		{
			cout << "Źle!" << endl;
		}
	} while (slowoUzytkownika != sekretneSlowo); // Zaczynamy od nowa, aż użytkownik zgadnie słowo

	return 0;
}

Jak widać kod tego programu wcale nie jest bardzo obszerny, a najlepiej go czytać zaczynając od funkcji main(). Zwróć uwagę na realizację poszczególnych etapów, jeden pod drugim. Dzięki temu że zostały wyraźnie oddzielone od siebie, łatwe jest je zrozumieć.

10.2.2. Objaśnienia

Poniżej znajduje się szczegółowy opis całego programu, który pomoże Ci dokładnie zrozumieć sposób jego działania.

Etap 1: wpisanie słowa

To był najłatwiejszy z wszystkich etapów. Polegał na wyświetleniu prośby o wpisanie słowa za pomocą instrukcji cout i zapisaniu go w zmiennej sekretneSlowo przy użyciu instrukcji cin.

Etap 2: mieszanie liter

To z kolei był najtrudniejszy z etapów. Jego realizacja została opracowana w formie funkcji o nazwie mieszajLitery (definicja znajduje się na początku programu). Funkcja main() wywołuje tę funkcję i przekazuje jej wpisane przez pierwszego gracza słowo. Zadaniem funkcji mieszajLitery jest zwrócenie pomieszanego słowa, które zostaje zapisane w zmiennej pomieszaneSlowo.

Przeanalizujemy budowę tej funkcji. Pobiera ona losowo po jednej literze słowa i robi to dopóki nie wybierze wszystkich liter.

while (slowo.size() != 0)
{
    pozycja = rand() % slowo.size();
    mieszanka += slowo[pozycja];
    slowo.erase(pozycja, 1);
}

W każdej iteracji pętli losowana jest liczba z przedziału od 0 do liczby liter pozostałych w słowie. Wylosowane litery dodawane są do łańcucha mieszanka i od razu usuwane z oryginalnego słowa, aby nie mogły być wylosowane więcej niż jeden raz.

Po wybraniu wszystkich liter kończy się wykonywanie pętli i zostaje zwrócona zmienna mieszanka zawierająca litery oryginalnego słowa w pomieszanej kolejności.

Etap 3: poproszenie drugiego gracza, aby odgadł słowo

Ten etap jest zrealizowany w formie pętli do ... while, dzięki czemu mamy gwarancję, że prośba o wpisanie słowa zostanie wyświetlona przynajmniej raz.

Słowo wpisane przez użytkownika jest odbierane przez instrukcję cin. Następnie jest ono porównywane z zawartością zmiennej sekretneSlowo. Pętla powtarza cykl dopóki nie zostanie wpisane takie same słowo, jak te, które znajduje się w zmiennej sekretneSlowo.

} while (slowoUzytkownika != sekretneSlowo); // Zaczynamy od nowa, aż użytkownik zgadnie słowo

W zależności od tego, czy wpisane słowo zgadza się z oryginałem, czy nie, wyświetlany jest odpowiedni napis. Koniec programu następuje w momencie wyjścia z tej pętli, które jednocześnie oznacza, że sekretne słowo zostało odgadnięte.

10.2.3. Pobieranie kodu źródłowego

Kod źródłowy gry można pobrać tutaj.

Plik ten możesz wykorzystać jako bazę do dalszej rozbudowy gry wg wskazówek opisanych w następnym podrozdziale.

10.3. Udoskonalanie gry

Skończyliśmy pracę nad programem, ale jak zawsze można w nim coś poprawić. Poniżej przedstawiam kilka propozycji udoskonaleń, których implementacja pozwoli Ci zdobyć jeszcze więcej praktycznych umiejętności programowania:

Jeśli masz jeszcze jakieś inne pomysły, to spróbuj je zrealizować. Im więcej będziesz ćwiczyć, tym efektywniejsza będzie Twoja nauka

Podsumowanie

Jestem pewien, że wykonanie tego projektu pozwoliło Ci dokonać większego postępu niż lektura wszystkich poprzednich rozdziałów. Nie ograniczaj się tylko do tego, co ja zaproponowałem. Wymyśl własne udoskonalenia do gry i je zaimplementuj. Jeśli utkniesz na czymś i nie będziesz wiedział, co robić dalej, możesz przecież zawsze poszukać pomocy na licznych forach internetowych.

Exit mobile version