Sprawdź się
Zadanie 4
Szkolne koło naukowe ENIGMA organizuje międzyklasowy konkurs kalamburów. Przygotowany został zbiór haseł przeznaczonych na pierwszą rundę rozgrywek. Aby uniknąć ujawnienia wybranych wyrazów przed rozpoczęciem konkursu, zostałeś poproszony o ich odpowiednie zabezpieczenie według otrzymanych wytycznych.
Treść wytycznych:
Każde hasło przygotowane na konkurs powinno zostać zaszyfrowane z wykorzystaniem szyfru Playfair.
Działanie szyfru Playfair
Szyfr Playfair bazuje na wykorzystaniu specjalnej tabeli szyfrującej. Składa się ona z 25 niepowtarzających się liter alfabetu łacińskiego ułożonych w kwadracie 5 na 5 znaków. Tworzenie kwadratu rozpoczynamy od wyboru słowa szyfrującego (kluczowego) – to jego literami wypełniamy pierwsze komórki tabeli. Jeśli jakaś litera występuje w słowie kluczowym więcej niż raz, to kolejne jej wystąpienia ignorujemy (nie wstawiamy tej litery po raz kolejny do tablicy). Resztę pustych miejsc wypełniamy pozostałymi (niewystępującymi w słowie szyfrującym) literami alfabetu według standardowej kolejności alfabetycznej. Przyjmujemy, że litery I oraz J zajmują to samo miejsce w tabeli.
Szyfrowanie wybranego tekstu jawnego rozpoczynamy od podziału go na pary liter. Jeśli w tekście występują znaki inne niż litery, np. znaki interpunkcyjne lub spacje, należy je wcześniej usunąć. Jeżeli ostatniej literze brakuje pary, dodajemy do niej kolejną literę w alfabecie (jeśli ostatnią literą jest Z, parę uzupełniamy literą A).
Z przygotowaną tablicę szyfrującą oraz tekstem jawnym podzielonym na pary, możliwe jest przeprowadzenie procesu szyfrowania. Polega ono na wykonaniu odpowiedniej operacji dla każdej z par znaków. Typ operacji zależy od umiejscowienia liter w kwadracie szyfrującym.
Możliwe warianty:
Jeśli obie litery znajdują się w tym samym wierszu tabeli, każda z nich zostaje zamieniona na literę sąsiadującą z nią po prawej stronie. Dodatkowo, jeśli któraś z liter umiejscowiona jest na ostatniej pozycji w wierszu (czyli w tabeli nie ma litery sąsiadującej z nią po prawej stronie), wówczas zostaje ona zamieniona na literę z pierwszej kolumny danego wiersza.
Jeśli obie litery znajdują się w tej samej kolumnie tabeli, każda z nich zostaje zamieniona na literę sąsiadującą poniżej. Analogicznie do zasady pierwszej: jeżeli rozpatrywana litera nie posiada sąsiada na dole, wówczas pobieramy literę z pierwszego wiersza tej samej kolumny.
Jeśli litery z danej pary nie są ani w tej samej kolumnie, ani w tym samym wierszu, literę aktualnie szyfrowaną zastępujemy znakiem, który znajduje się na przecięciu wiersza wyznaczanego przez szyfrowaną literę, oraz kolumny, w której jest zapisana druga litera z pary.
W pliku dane.txt znajduje się 10 wierszy z hasłami konkursowymi oraz kluczami do ich zaszyfrowania. Każdy wiersz zawiera dwa oddzielone pojedynczym znakiem spacji słowa (ciągi znaków) złożone z wielkich liter alfabetu łacińskiego (z pominięciem litery J) o maksymalnej długości 20 znaków. Pierwszy wyraz to klucz szyfrujący, drugi – hasło do zaszyfrowania.
W wybranym języku programowania napisz program, który za pomocą szyfru Playfair zaszyfruje podane hasła konkursowe z wykorzystaniem odpowiadających im kluczy szyfrujących. Otrzymany szyfrogramy zapisz w pliku wyniki.txt w oddzielnych wierszach zgodnie z kolejnością danych w pliku dane.txt.
Przykładowe dane:
BANAN EGZEGEZA
APOTEOZA AMBIWALENTNY
PLIK FOLDEROdpowiedź dla przykładowych danych:
FHVIHFWD
ZUCHUOSFRPSV
OUICCTPlik dane.txt:
Przycisk do pobrania pliku TXT z treścią zadania. Pobierz załącznik
Do oceny oddajesz:
plik
wyniki.txtz odpowiedzią (zaszyfrowanymi słowami z plikudane.txt; każde w osobnej linii z zachowaniem identycznej kolejności jak w pliku wejściowym);plik(i) z komputerową realizacją zadania (kodem programu).
Działanie programów zapisanych w testerkach przetestuj dla klucza BANAN oraz hasła EGZEGEZA.
JĘZYK C++
Przykładowe rozwiązanie zadania:
#include <iostream>
#include <utility>
#include <vector>
using namespace std;
string usunDuplikaty(string slowo)
{
string wynik = "";
bool spotkane[26];
for (int i = 0; i < 26; i++)
{
spotkane[i] = false;
}
for (int i = 0; i < slowo.length(); i++)
{
char znak = slowo[i];
if (!spotkane[znak - 'A'])
{
wynik += znak;
spotkane[znak - 'A'] = true;
}
}
return wynik;
}
vector<vector<char>> generujKwadrat(string slowo)
{
vector<vector<char>> kwadrat = vector<vector<char>>(5, vector<char>(5, 'A'));
slowo = usunDuplikaty(slowo);
char znak = 'A';
for (int i = 0; i < 25; i++)
{
int y = i / 5;
int x = i % 5;
if (i < slowo.length())
{
kwadrat[y][x] = slowo[i];
continue;
}
while (slowo.find(znak) != slowo.npos || znak == 'J')
{
znak++;
}
kwadrat[y][x] = znak++;
}
return kwadrat;
}
pair<int, int> pozycjaZnaku(vector<vector<char>> kwadrat, char znak)
{
for (int y = 0; y < 5; y++)
{
for (int x = 0; x < 5; x++)
{
if (kwadrat[y][x] == znak) return make_pair(x, y);
}
}
throw 1;
}
string zakodujPare(char znak1, char znak2, vector<vector<char>> kwadrat)
{
pair<int, int> pozycja1 = pozycjaZnaku(kwadrat, znak1);
pair<int, int> pozycja2 = pozycjaZnaku(kwadrat, znak2);
string zakodowany = "";
if (pozycja1.second == pozycja2.second)
{
zakodowany += kwadrat[pozycja1.second][(pozycja1.first + 1) % 5];
zakodowany += kwadrat[pozycja2.second][(pozycja2.first + 1) % 5];
}
else if (pozycja1.first == pozycja2.first)
{
zakodowany += kwadrat[(pozycja1.second + 1) % 5][pozycja1.first];
zakodowany += kwadrat[(pozycja2.second + 1) % 5][pozycja2.first];
}
else
{
zakodowany += kwadrat[pozycja1.second][pozycja2.first];
zakodowany += kwadrat[pozycja2.second][pozycja1.first];
}
return zakodowany;
}
string zakoduj(vector<vector<char>> kwadrat, string tekst)
{
if (tekst.length() % 2 == 1)
{
if (tekst[tekst.length() - 1] == 'Z')
{
tekst += 'A';
}
else
{
tekst += char(int(tekst[tekst.length() - 1]) + 1);
}
}
string zaszyfrowany = "";
for (int i = 0; i < tekst.length(); i += 2)
{
zaszyfrowany += zakodujPare(tekst[i], tekst[i + 1], kwadrat);
}
return zaszyfrowany;
}
int main()
{
string klucz = "BANAN";
string slowo = "EGZEGEZA";
vector<vector<char>> kwadrat = generujKwadrat(klucz);
cout << zakoduj(kwadrat, slowo);
return 0;
}JĘZYK JAVA
Przykładowe rozwiązanie zadania:
public class Main {
public static void main(String[] args) {
String klucz = "BANAN";
String slowo = "EGZEGEZA";
char[][] kwadrat = generujKwadrat(klucz);
System.out.println(zakoduj(kwadrat, slowo));
}
private static String usunDuplikaty(String slowo) {
StringBuilder wynik = new StringBuilder();
boolean[] spotkane = new boolean[26];
for (char znak : slowo.toCharArray()) {
if (!spotkane[znak - 'A']) {
wynik.append(znak);
spotkane[znak - 'A'] = true;
}
}
return wynik.toString();
}
private static char[][] generujKwadrat(String slowo) {
char[][] kwadrat = new char[5][5];
char znak = 'A';
slowo = usunDuplikaty(slowo);
for (int i = 0; i < 25; i++) {
int y = i / 5;
int x = i % 5;
if (i < slowo.length()) {
kwadrat[y][x] = slowo.charAt(i);
continue;
}
while (slowo.indexOf(znak) != -1 || znak == 'J') {
znak++;
}
kwadrat[y][x] = znak++;
}
return kwadrat;
}
private static Punkt pozycjaZnaku(char znak, char[][] kwadrat) {
for (int y = 0; y < kwadrat.length; y++) {
for (int x = 0; x < kwadrat[y].length; x++) {
if (kwadrat[y][x] == znak) return new Punkt(x, y);
}
}
throw new IllegalArgumentException("Podany znak nie występuje w tablicy!");
}
private static String zakodujPare(char znak1, char znak2, char[][] kwadrat) {
Punkt pozycja1 = pozycjaZnaku(znak1, kwadrat);
Punkt pozycja2 = pozycjaZnaku(znak2, kwadrat);
if (pozycja1.getY() == pozycja2.getY()) {
return "" + kwadrat[pozycja1.getY()][(pozycja1.getX() + 1) % 5] + kwadrat[pozycja2.getY()][(pozycja2.getX() + 1) % 5];
}
if (pozycja1.getX() == pozycja2.getX()) {
return "" + kwadrat[(pozycja1.getY() + 1) % 5][pozycja1.getX()] + kwadrat[(pozycja2.getY() + 1) % 5][pozycja2.getX()];
}
return "" + kwadrat[pozycja1.getY()][pozycja2.getX()] + kwadrat[pozycja2.getY()][pozycja1.getX()];
}
private static String zakoduj(char[][] kwadrat, String tekst) {
if (tekst.length() % 2 == 1) {
if (tekst.charAt(tekst.length() - 1) == 'Z') {
tekst += 'A';
}
else {
tekst += (char) (((int) tekst.charAt(tekst.length() - 1)) + 1);
}
}
StringBuilder zaszyfrowany = new StringBuilder();
for (int i = 0; i < tekst.length(); i += 2) {
zaszyfrowany.append(zakodujPare(tekst.charAt(i), tekst.charAt(i + 1), kwadrat));
}
return zaszyfrowany.toString();
}
}
class Punkt {
private int x, y;
public Punkt(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}JĘZYK PYTHON
Przykładowe rozwiązanie zadania:
def usun_duplikaty(slowo):
spotkane = []
wynik = ""
for znak in slowo:
if znak not in spotkane:
wynik += znak
spotkane.append(znak)
return wynik
def stworz_kwadrat(slowo):
kwadrat = [['A' for x in range(5)] for y in range(5)]
znak = 'A'
slowo = usun_duplikaty(slowo)
for i in range(25):
y = int(i / 5)
x = i % 5
if i < len(slowo):
kwadrat[y][x] = slowo[i]
continue
while znak in slowo or znak == 'J':
znak = chr(ord(znak) + 1)
kwadrat[y][x] = znak
znak = chr(ord(znak) + 1)
return kwadrat
def pozycja_znaku(znak, kwadrat):
for i in range(5):
for j in range(5):
if kwadrat[i][j] == znak:
return [i, j]
def zakoduj_pare(para, kwadrat):
y1, x1 = pozycja_znaku(para[0], kwadrat)
y2, x2 = pozycja_znaku(para[1], kwadrat)
if y1 == y2:
return kwadrat[y1][(x1 + 1) % 5] + kwadrat[y2][(x2 + 1) % 5]
if x1 == x2:
return kwadrat[(y1 + 1) % 5][x1] + kwadrat[(y2 + 1) % 5][x2]
else:
return kwadrat[y1][x2] + kwadrat[y2][x1]
def zakoduj(kwadrat, tekst):
if len(tekst) % 2 == 1:
if tekst[len(tekst) - 1] == "Z":
tekst += "A"
else:
tekst += chr(ord(tekst[len(tekst) - 1]) + 1)
zaszyfrowany = ""
for i in range(len(tekst)):
if i % 2 == 0:
zaszyfrowany += zakoduj_pare(tekst[i] + tekst[i + 1], kwadrat)
return zaszyfrowany
klucz = "BANAN"
slowo = "EGZEGEZA"
kwadrat = stworz_kwadrat(klucz)
print(zakoduj(kwadrat, slowo))Odpowiedź do zadania
Odpowiedź do zadania dla danych z pliku dane.txt:
Przycisk do pobrania pliku TXT z wynikiem zadania. Pobierz załącznik
szyfr.txt.