Pomoce:

Biblioteka procedur obsługi konsoli znakowej - newconio


Łańcuchy znakowe

Łańcuchy znakowe są wygodnym typem danych do przetwarzania tekstów. W bibliotece STL mamy zdefiniowana klasę string, która umożliwia wykonywanie różnych operacji na łańcuchach znakowych. Klasa jest strukturą danych, z którą powiązane są tzw. funkcje składowe, czyli funkcje operujące bezpośrednio na tej strukturze, Dostęp do klasy string uzyskujemy po dołączeniu do naszego programu źródłowego pliku nagłówkowego:

 

#include <string>

 

Zmienną typu string definiujemy jak każdą inną zmienną w C++:

 

string nazwa_zmiennej;

 

Tak zdefiniowana zmienna nie zawiera w sobie żadnego znaku. Mówimy, że jest pustym łańcuchem znakowym. Tekst możemy wprowadzić do łańcucha np. za pomocą instrukcji przypisania:

 

// Klasa string
// (C)2010 ILO w Tarnowie
// KOŁO INFORMATYCZNE
//-----------------------

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string s;

    s = "ALA MA KOTA";

    cout << s << endl;

    return 0;
}

 

Na łańcuchach zdefiniowany jest operator dodawania +. W tym przypadku oznacza on łączenie ze sobą łańcuchów:

 

// Klasa string
// (C)2010 ILO w Tarnowie
// KOŁO INFORMATYCZNE
//-----------------------

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string s1,s2,s3;

    s1 = "MISIEK";
    s2 = "BUBU";
    s3 = s1 + " " + s2;

    cout << s3 << endl;

    return 0;
}

 

Zawartość łańcucha można odczytać ze strumienia cin:

 

// Klasa string
// (C)2010 ILO w Tarnowie
// KOŁO INFORMATYCZNE
//-----------------------

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string s;

    cin >> s; cout << s << endl;

    return 0;
}

 

Jednakże ten sposób wprowadzania danych nie zawsze jest dogodny, ponieważ spacja jest traktowana przez strumień jako separator. Zatem tekst zostanie wprowadzony tylko do pierwszej spacji, po czym wprowadzanie zakończy się. Dalszą część tekstu można odczytać kolejną operacją cin >>. Uruchom ponownie poprzedni program i wpisz dwa wyrazy rozdzielone spacją. Zwróć uwagę na wynik. Spróbuj jeszcze wprowadzić tekst pusty, naciskając sam klawisz Enter, lub same spacje - nie da się, prawda? Teraz wprowadź poniższy program i spróbuj ponownie wprowadzić dwa wyrazy rozdzielone spacją

 

// Klasa string
// (C)2010 ILO w Tarnowie
// KOŁO INFORMATYCZNE
//-----------------------

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string s;

    cin >> s; cout << s << endl;
    cin >> s; cout << s << endl;

    return 0;
}

 

Rozwiązaniem tego problemu jest zastosowanie funkcji getline(). Przyjmuje ona dwa parametry:

 

getline(strumień,łańcuch);

 

strumień  - z którego odczytujemy znaki
łańcuch  - zmienna łańcuchowa, do której trafią odczytane znaki.

 

// Klasa string
// (C)2010 ILO w Tarnowie
// KOŁO INFORMATYCZNE
//-----------------------

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string s;

    getline(cin,s);
    cout << s << endl;

    return 0;
}

 

Funkcja getline() odczytuje ze strumienia jeden wiersz tekstu. Problemy mogą się jednak pojawić, jeśli w programie mieszamy  metodę odczytu cin >> z getline(). Pierwsza metoda nie usuwa ze strumienia znaku końca wiersza. Jeśli bezpośrednio po niej zastosujemy getline(), to zamiast odczytu wiersza znaków, zostanie odczytany pozostawiony w strumieniu znak końca wiersza z poprzedniego cin >>. W efekcie odczytany wiersz znaków będzie pusty!!!

 

// Klasa string
// (C)2010 ILO w Tarnowie
// KOŁO INFORMATYCZNE
//-----------------------

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string s;
    int a;

    cin >> a;

    getline(cin,s);
    cout << s << endl;

    return 0;
}

 

W powyższym programie wprowadź dowolną liczbę. Po jej wprowadzeniu program powinien odczytać ciąg znaków. Jednakże kończy się z pustym łańcuchem s, ponieważ odczyt cin >> a; pozostawił w strumieniu znak końca wiersza \n. Teraz getline() odczytuje ten znak i w efekcie do s  trafia pusta linia tekstu - użytkownik nie ma nawet okazji nic wpisać. Problem ten można rozwiązać za pomocą funkcji składowej cin.ignore(liczba_znaków_do_usunięcia,znak), która usuwa zadaną ilość znaków, aż do napotkania wskazanego znaku. Funkcję tę stosujemy po operacji cin >> następująco:

 

// Klasa string
// (C)2010 ILO w Tarnowie
// KOŁO INFORMATYCZNE
//-----------------------

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string s;
    int a;

    cin >> a; cin.ignore(256,'\n');

    getline(cin,s);
    cout << s << endl;

    return 0;
}

 

Dostęp do poszczególnych znaków łańcucha uzyskujemy za pomocą indeksów, jak w zwykłej tablicy. Ilość znaków przechowywanych w łańcuchu udostępnia nam funkcja składowa:

 

łańcuch.length()

 

Poniższy program odczytuje dowolny tekst, a następnie zastępuje w nim literki "a" literkami "i", a literki "i" literakami "a".

 

// Klasa string
// (C)2010 ILO w Tarnowie
// KOŁO INFORMATYCZNE
//-----------------------

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string s;
    int i,n;

    getline(cin,s);

    n = s.length();

    for(i = 0; i < n; i++)
        if(s[i] == 'a')      s[i] = 'i';
        else if(s[i] == 'i') s[i] = 'a';

    cout << s << endl;
    return 0;
}

 


 

Master Mind

obrazek

Mini Master Mind jest grą logiczną rozwijającą inteligencję. Nie jest to gra prymitywna. Kiedyś zdobyła olbrzymią popularność na całym świecie. Do dzisiaj w sklepach z zabawkami można jeszcze kupić zestaw do gry w Master Mind. W oryginalnej grze celem było odgadnięcie kodu przeciwnika, który składał się z kolorowych pionów - cztery piony wybrane spośród 6 kolorów. Kolory mogły się powtarzać. U nas, zamiast kolorowych pionów, będą literki A, B, C, D, E i F.
 

Zasady Mini Master Minda
  1. Gracz nr 1 wybiera kod zbudowany z czterech liter wybranych spośród 6. Litery w kodzie mogą się powtarzać.
  2. Gracz nr 2 wprowadza swój kod koloru.
  3. W odpowiedzi gracz nr 1 analizuje wprowadzony kod i podaje informację o jego zgodności ze swoim kodem za pomocą literek o i x (w oryginalnej grze były to specjalne piony białe i czarne). Literka o oznacza, iż litera w kodzie gracza nr 2 zgadza się z literą w tajnym kodzie gracza nr 1, jednakże jest na złej pozycji. Litera x oznacza, iż w kodzie obu graczy na tej samej pozycji występuje ta sama litera. Oczywiście gracz nr 2 nie wie, która z liter jego kodu jest na właściwej pozycji - musi to sobie odgadnąć.
  4. Gra kończy się, gdy gracz nr 2 odgadnie kod gracza nr 1 otrzymując cztery litery x lub wykorzysta limit 6 ruchów. W przeciwnym razie wracamy do punktu 2.


Aby lepiej zrozumieć zasady tej gry, przyjrzyjmy się przykładowej rozgrywce. W rzeczywistej grze kod gracza nr 1 nie jest widoczny - tutaj pokazujemy go specjalnie, aby czytelnik mógł sobie sprawdzić odpowiedzi na przykładowe kody, które wprowadził gracz nr 2.
 

Runda Kody Odp. Opis
 
EBDC
  To jest przykładowy kod wprowadzony przez gracza nr 1. Kod ten musi odgadnąć gracz nr 2.
1.
CBAD
xoo Ten kod wprowadza gracz nr 2. W odpowiedzi gracz nr 1 wypisuje jedną literkę x oraz dwie literki o, ponieważ litery B zgadzają się w obu kodach, a C i D są na złych pozycjach. Oczywiście gracz nr 1 nie wie o które kolory chodzi - musi to odgadnąć na podstawie analizy swoich ruchów i otrzymanych na nie odpowiedzi.
2.
CDBE
oooo Gracz nr 1 założył, iż dobrą literą była litera C, a pozostałe przemieścił, wymieniając A na E. Odpowiedź gracza nr 1 oznacza, iż trafione zostały wszystkie litery, ale są one na niewłaściwych pozycjach w obu kodach.
3.
DCEB
oooo Gracz nr 1 zmienia pozycję wszystkich liter w swoim kodzie. Ważne, aby dokonać tego z głową. Litery są wciąż na niewłaściwych pozycjach. Dokonujemy kolejnej permutacji...
4.
EBCD
xxoo Dwie litery są na niewłaściwych pozycjach. Czy z ruchów gracza nr 2 i z odpowiedzi gracza nr 1 potrafiłbyś wysnuć wniosek, o które z nich chodzi? Rusz głową.

 

W naszej rozgrywce będzie uczestniczył człowiek i komputer. Każdy z nich może być jednym z dwóch graczy - szyfrantem i łamaczem kodu. Schemat gry będzie następujący:

 

Na początku gracz decyduje kim chce być: szyfrantem czy łamaczem kodu. Jeśli wybiera rolę szyfranta, to wymyśla swój czteroliterowy kod z literek A...F. Jeśli wybierze rolę łamacza kodu, to komputer generuje tajny kod, który gracz będzie musiał odgadnąć.

Rozpoczyna się seria 6 rund. Jeśli gracz jest łamaczem kodu, to w każdej rundzie wprowadza swój kod, na który komputer generuje odpowiedź z literek x i o. Jeśli gracz odgadnie kod komputera, gra się kończy zwycięstwem człowieka. Jeśli w ciągu 6 rund kod nie zostanie złamany, człowiek przegrywa - komputer wyświetla wtedy odpowiedni komunikat oraz podaje swój kod, którego gracz nie odgadnął.

Jeśli człowiek jest szyfrantem, to komputer generuje swój kod, który następnie człowiek ocenia wpisując literki x i o. Dalsze zasady są takie same jak dla człowieka.

 

W grze tej pojawiają się dwa problemy:

  1. Generowanie kodu odpowiedzi z x i o na podstawie kodu tajnego oraz kodu wprowadzonego przez gracza. Zadanie to rozwiązujemy w dwóch krokach. Pracujemy zawsze na kopiach tych kodów, a nie na ich oryginałach. W pierwszym kroku porównujemy kolejne znaki obu kodów. Jeśli natrafimy na zgodność, dopisujemy do odpowiedzi x. Następnie usuwamy te znaki w obu kodach, aby nie zostały ponownie zaliczone. W drugim kroku sprawdzamy każdy znak jednego kodu z każdym znakiem kodu drugiego. Jeśli znajdziemy zgodność, to do odpowiedzi dopisujemy o, a znaki w obu kodach usuwamy, aby nie zostały zaliczone ponownie.

  2. Wybór kodu przez komputer. Zadanie to rozwiązujemy tworząc tablicę wszystkich możliwych kodów czteroliterowych, zbudowanych z 6 dozwolonych liter A...F. W tablicy tej wybieramy losowo jeden z kodów. Następnie odczytujemy jego ewaluację przez człowieka. Teraz dokonujemy pewnej sztuczki. Przyjmujemy, że wybrany przez nas kod, jest kodem tajnym. Porównujemy go ze wszystkimi kodami w tablicy, generując odpowiedzi z x i o. Jeśli różnią się one od odpowiedzi otrzymanej od człowieka, to dany kod w tablicy nie może być poszukiwanym kodem (dlaczego?). Usuwamy go z tablicy. Gdy zrobimy to ze wszystkimi kodami, w tablicy pozostaną jedynie takie, które dają zgodne odpowiedzi z odpowiedzią człowieka. Wśród nich musi znajdować się kod człowieka. W następnej turze całą operacje powtarzamy z kodami pozostawionymi w tablicy. Ilość ich za każdym razem maleje, aż w końcu pozostanie tylko jeden kod - tajny kod człowieka..

// Gra MASTER MIND
// (C)2010 ILO w Tarnowie
// KOŁO INFORMATYCZNE
//-----------------------

#include <iostream>
#include <string>
#include <cstdlib>
#include <time.h>

using namespace std;

// funkcja dokonuje ocent dwóch kodów, dając w odpowiedzi
// ciąg x i o zgodnie z regułami gry
//-------------------------------------------------------

string ocena_kodow(string kod1,string kod2)
{
    string wynik = "";

    // najpierw sprawdzamy zgodność znaków na tych samych pozycjach

    for(int i = 0; i < 4; i++)
        if(kod1[i] == kod2[i])
        {
            wynik += "x";
            kod1[i] = '#'; kod2[i] = '$';
        }

    // teraz sprawdzamy zgodność znaków na różnych pozycjach

    for(int i = 0; i < 4; i++)
      for(int j = 0; j < 4; j++)
        if(kod1[i] == kod2[j])
        {
            wynik += "o";
            kod2[j] = '$';
            break;
        }
    return wynik;
}

int main()
{
    bool koder;                 // false - koduje człowiek, true - koduje komputer
    string tajny_kod;           // kod do odgadywania
    string kod_gracza;          // kod wprowadzany przez gracza
    string odpowiedz;           // ewaluacja kodu z literek x i o
    string tablica_kodow[1296]; // tablica wszystkich kodów
    int liczba_kodow;           // określa ile jest kodów w tablicy

    // inicjujemy generator pseudolosowy

    srand((unsigned)time(NULL));

    // tworzymy tablicę wszystkich kodów

    for(int i = 0; i < 1296; i++)
    {
        string kod = "    ";
        int v = i;
        kod[0] = 65 + v / 216; v = v % 216;
        kod[1] = 65 + v /  36; v = v %  36;
        kod[2] = 65 + v /   6; v = v %   6;
        kod[3] = 65 + v;
        tablica_kodow[i] = kod;
    }

    liczba_kodow = 1296;

    // powitanie w grze, określamy, kto jest koderem, a kto łamaczem kodu

    cout << "MASTER MIND\n"
            "-----------\n\n"
            "(C)2010 KOLO INFORMATYCZNE w I-LO w Tarnowie\n\n"
            "Czy chcesz byc koderem? : ";

    getline(cin,odpowiedz);

    cout << endl << endl;

    koder = (odpowiedz[0] != 't') && (odpowiedz[0] != 'T');

    // Jeśli komputer jest koderem, to generuje tajny kod

    if(koder)
    {
        tajny_kod = "";
        for(int i = 0; i < 4; i++) tajny_kod += 65 + rand() % 6;
    }

    // rozpoczynamy rozgrywkę z 6 rund

    for(int runda = 1; runda <= 6; runda++)
    {
        cout << "RUNDA NR " << runda << " : ";

        // jeśli koderem jest komputer, to gracz wprowadza swój kod,
        // inaczej komputer wybiera losowy kod z tablicy kodów

        if(koder)
        {
            getline(cin,kod_gracza);
            while(kod_gracza.length() < 4) kod_gracza += " ";
        }
        else
        {
            kod_gracza = tablica_kodow[rand() % liczba_kodow];
            cout << kod_gracza << endl;
        }

        // jeśli koderem jest komputer, to on ocenia kod gracza
        // inaczej gracz wprowadza swoja ocenę, a komputer eliminuje
        // nie pasujące do niej kody z tablicy

        cout << "                  : ";
        if(koder)
        {
            odpowiedz = ocena_kodow(tajny_kod,kod_gracza);
            cout << odpowiedz << endl;
        }
        else
        {
            getline(cin,odpowiedz);

            int i,j;

            for(j = i = 0; i < liczba_kodow; i++)
                if(odpowiedz == ocena_kodow(kod_gracza,tablica_kodow[i]))
                    tablica_kodow[j++] = tablica_kodow[i];

            liczba_kodow = j;
        }

        if(odpowiedz == "xxxx") break;
    }

    // koniec gry.

    if(odpowiedz == "xxxx")
        cout << endl << "### GRATULACJE ###" << endl;
    else if(koder)
        cout << endl << "NIE ODGADLES " << tajny_kod << endl;

    return 0;
}

 

Uwaga: w tej uproszczonej wersji program nie jest odporny na błędne wprowadzenie danych przez użytkownika.

 


   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2024 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe