czwartek, 16 czerwca 2011

Szyfr przestawieniowy w C++

Ostatnio trochę grzebałem w zadaniach maturalnych z informatyki i trafiłem na polecenie napisania aplikacji używającej szyfru przestawieniowego opartego na macierzy do zaszyfrowania dowolnego tekstu. Długo się nie zastanawiając machnąłem sobie programik, którym mam zamiar się z wami podzielić i przy okazji nieco opisać jego bebechy. Kod programu z implementacją szyfru przestawieniowego:

#include <iostream>
#include <cstring>
#include <cmath>

using namespace std;

int main()
{
    string s = "ala ma kota a kot ma ale";
    string result = "";
    int matrix_size = ceil(sqrt(s.size()));
    char matrix[matrix_size][matrix_size];

    for (int i=0; i<matrix_size; i++) {
        for (int j=0; j<matrix_size; j++) {
            if ((i*matrix_size)+j >= s.length()) {
                matrix[i][j] = '_';
                continue;
            }
            matrix[i][j] = (s[(i*matrix_size)+j] == ' ' ? '_' : s[(i*matrix_size)+j]);
        }
    }

    for (int i=0; i<matrix_size; i++) {
        for (int j=0; j<matrix_size; j++)
            result += matrix[j][i];
    }

    cout << "Tekst zaszyfrowany: " << result << endl;

    return 0;
}

Zacznijmy od linii 15. Tam do wcześniej zdefiniowanego stringa wpisywany jest tekst, który chcemy zaszyfrować. Następnie obliczana jest długość tekstu (linia 17), zaś na jej podstawie program wylicza ilość kolumn i wierszów macierzy (linia 18), w której będzie umieszczony tekst. Funkcja sqrt() liczy pierwiastek z podanej liczby, natomiast ceil() zaokrągla w górę liczbę podaną jako argument. W linii 20 definiujemy macierz, do której następnie wpiszemy tekst do zaszyfrowania.
W liniach 23 - 29 mamy pętle, które wierszami, po jednej literce zapełniają każdą komórkę macierzy. Spacje zamieniane są na podkreślnik. Gdy ilość komórek jest większa od ilości znaków w tekście, końcowe komórki macierzy również są wypełniane podkreślnikami. Po wypełnieniu macierzy znakami w liniach 32 - 37 tekst z tablicy jest spisywany kolumnami do stringa result. W linii 40 na urządzenie wyjścia wypisywany jest zaszyfrowany tekst.

Jest to chyba najprostszy możliwy sposób w jaki można zaimplementować algorytm szyfrowania przestawieniowego.

sobota, 14 maja 2011

Algorytm losujący #1

Podstawowe biblioteki C++ nie oferują zbyt wiele w zakresie generowania losowości – zwłaszcza w kwestii generowania liczb losowych z określonego przez nas przedziału. Mamy co prawda funkcję rand() zdefiniowaną w pliku cstdlib (stdlib.h), jednakże jest ona dość niewygodna do stosowania w niektórych sytuacjach, nie biorąc już nawet pod uwagę zmniejszenia przejrzystości kodu.

Bardzo dobrą praktyką jest napisanie własnej implementacji funkcji losującej dostosowanej do naszych potrzeb. Poniżej przedstawię i opiszę jeden z wielu algorytmów, które bazują na funkcji rand() z biblioteki standardowej.

Schemat blokowy algorytmu


Kod funkcji losującej:

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

using namespace std;

int main()
{
    int min, max, result;
    cout << "Podaj dolna granice przedzialu: ";
    cin >> min;
    cout << "Podaj gorna granice przedzialu: ";
    cin >> max;

    if (max >= min) {
        max -= min;
    } else {
        int tmp = min - max;
        min = max;
        max = tmp;
    }

    srand(time(NULL));

    if (max < 0) {
        result = min;
    } else {
        result = (rand()%max) + min;
    }

    cout << "Wynik: " << result;

    return 0;
}


Jak widać algorytm ten nie jest zbyt skomplikowany. Przyjmuje dwa argumenty: min (minimalna liczba jaką chcemy wylosować) i max (maksymalna liczba jaką chcemy wylosować). Następnie sprawdzane jest, czy maksymalna liczba jest większa lub równa minimalnej. Jest to takie małe zabezpieczenie, w przypadku gdyby ktoś korzystający z tego algorytmu pomylił się podczas kodzenia. Jeśli minimalna liczba jest większa od maksymalnej, ich wartości zostają zamienione miejscami. Dodatkowo w zarówno jednym, jak i drugim wyniku warunku od wartości maksymalnej odejmowana jest minimalna, co daje nam ilość możliwych wylosowanych liczb. Później sprawdzane jest czy owa ilość jest większa od zera, a jeśli nie to ostatecznie funkcja zwraca wartość minimalną (min). W przypadku gdy max jest większe od 0 za pomocą wbudowanej w biblioteki standardowe funkcji rand() losujemy liczbę. Wylosowana liczba podzielona przez ilość możliwych liczb do wylosowania daje resztę, do której dodajemy wartość minimalną. W efekcie otrzymujemy (pseudo)losową wartość z przedziału wprowadzonego na początku działania algorytmu.