• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Matura Maj 2016 Zadanie 6.2 (Rozwiązanie) (C++11)

VPS Starter Arubacloud
0 głosów
3,084 wizyt
pytanie zadane 14 kwietnia 2018 w Rozwój zawodowy, nauka, praca przez Krzysiu Czereczon Nowicjusz (170 p.)
edycja 14 kwietnia 2018 przez Krzysiu Czereczon

To zadanie miało błąd w pliku, lecz na potrzeby ćwiczeń starałem się naprawić ten problem, a mianowicie każda linijka w pliku składała się z zakodowanego słowa oraz klucza do odszyfrowania go, niektóre z tych linijek nie miały klucza w tym miejscu powinno być 0, lecz jest tam spacja.

Wiem, że powinienem użyć metody "strtok", ale zważywszy na to, że na egzaminie maturalnym nie mamy dostępu do internetu, a zapamiętywanie kolejnych fukcji na siłe nie jest dobre postanowiłem plik "Dane_6_2.txt" podzielić w MS Access, dzięki temu mogłem zastosować znane wszystkim "std::getline". Przedstawiam moje rozwiązanie może się komuś przyda na przyszłość, albo teraz klika tygodni przed maturą.

Zadanie 6.1: https://forum.pasja-informatyki.pl/343013/matura-maj-2016-zadanie-6-1-rozwiazanie

 

Treść zadania:

W pliku dane_6_2.txt zapisano 3 000 szyfrogramów i odpowiadające im klucze
szyfrujące. W każdym wierszu znajduje się jeden szyfrogram (zaszyfrowane słowo)
i po pojedynczym znaku odstępu odpowiadający mu klucz (maksymalnie czterocyfrowa
liczba).

Fragment pliku dane_6_2.txt:

BCYKUNCM 1718
YFOGNSKGYW 7580
WARDA 9334 

Napisz program, który odszyfruje słowa zaszyfrowane podanymi kluczami. Wynik zapisz
w pliku wyniki_6_2.txt: każde odszyfrowane słowo w osobnym wierszu, w porządku
odpowiadającym kolejności szyfrogramów z pliku z danymi.

Uwaga:
Dla pierwszego szyfrogramu z pliku dane_6_2.txt (BCYKUNCM) wynikiem jest słowo
ZAWISLAK. 

 

Arkusz:


https://cke.gov.pl/images/_EGZAMIN_MATURALNY_OD_2015/Arkusze_egzaminacyjne/2016/formula_od_2015/MIN-R2_1P-162.pdf

 

Pliki:


https://www.cke.edu.pl/images/_EGZAMIN_MATURALNY_OD_2015/Arkusze_egzaminacyjne/2016/formula_od_2015/Dane_PR2.zip

 

Rozwiązanie:

#include <iostream>
#include <fstream> //biblioteka obsługi plików
#include <string>
#include <vector> //vektor ze standardu 11 coś jak dynamiczna tablica
#include <stdlib.h> //fukcja atoi


using namespace std;

char alfabet[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; // tablica znaków alfabetu
ifstream plik; //klasa pliku

string decryption(string in, int k) // fuckja zmieniająca zahasowane słowa na normalne
{
    string deHashedString; // zmienna pomocnicza
    for(int i = 0; in.length() >= i; i++) // petla wykonywujaca sie dla każdej literki
    {
        int j = -1; // zmienna pomocnicza ala iterator
        while(in[i] != alfabet[j]) // pętla w której badamy, którą literką z kolei jest nasza badana litera
        {
            j++; // jeśli warunek nie jest spełniony dodaje sie iterator oznaczający pozycje litery np liera "A" = 0
        }


        if(j != -1){ // sprawdzanie aby dla liczny -1 nie wykonała się dalsza część funckji
            int pointer = j - k%sizeof(alfabet); // ustalamy która liczbą w alfabecie była liczba wcześniej po wpisaniu kodu
            //modulo k oznacza tyle, że gdy klucz będzie większy niż 25 (ilość liter w alfabecie) zacznie liczenie od 0
            if(pointer < 0) // jeżeli nasza liczba jest na - oznacza to że zaczyna od końca alfabet (-1 oznacza 24)
            {
                deHashedString += alfabet[pointer+sizeof(alfabet)]; // dodawanie znaku do stringa gdy liczba jest < 0 dodajemy
                //dlugość tablicy znaków alfabetu otrzymujemy w ten sposób cofniecie się liczby do końca tablicy
            }
            else
            {
                deHashedString += alfabet[pointer]; // wypisuje normalną liczbę
            }
        }
    }
    return deHashedString; // zwraca stworzonego stringa
}

std::vector<std::string> getWords(string dir) // funkcja zwracająca vektor słow z danego pliku standard 11
{
    ifstream file; // zmienna wczytująca plik
    std::vector<std::string> lines; // vektor stringów

    file.open(dir); // otwiranie pliku
    if(file.good()) // sprawdzenie czy plik został wczytany
    {
        string currLine; // zmienna pomoicnicza
        while(std::getline(file,currLine)) // fukcja pobierająca każdą linijkę pliku
        {
            lines.push_back(currLine); // dodawanie do końca vektora naszej wartości
        }
    }
    file.close(); // zamykamy źródło pliku
    return lines; // zwracamy vektor słow
}

std::vector<int> stringToInt(std::vector<std::string> strings) // fukcja zamieniająca stringi na inta
{
    std::vector<int> ints; // vektor pomocniczy typu int
    for(string get: strings) // petla wykonywująca się dla każdego elementu w vektorze
    {
        ints.push_back(atoi(get.c_str())); // dodawanie na koniec vektora naszej nowej przekonwertowanej za pomocą fukcji atoi warości
        // ważne, aby strina zamienić na tablicę "charów", za to operacje odpowiedzialna jest metoda "c_str()"

    }

    return ints; // zwraca vektor typu int z przekonwertowanymi znakami
}

int main()
{
    std::vector<std::string> words = getWords("Words.txt"); // wczytywanie za pomocą funkcji słow
    std::vector<int> keys = stringToInt(getWords("Key.txt")); // wczytywanie za pomocą fukcji kluczy oraz przekonwertowanie ich na inty

    for (int i = 0; words.size() > i; i++) // petla wykonywująca sie dla każdego słowa w vektorze słów
    {
        string deHashedString = decryption(words.at(i), keys.at(i)); // towrzenie słowa, które po użyciu klucza staje sie zrozumiałe
        cout << deHashedString << endl; // zwaraca do konsoli nowo otrzymane słowo
    }

    return 0; // kończy program
}

 

komentarz 14 kwietnia 2018 przez niezalogowany
Nie lepiej bez kontenera vector? Tworzenie funkcji getWords/stringToInt strasznie wszystko komplikuje.
komentarz 14 kwietnia 2018 przez Krzysiu Czereczon Nowicjusz (170 p.)
funkcje getWords stworzyłem po to aby dwa razy nie robić tego samego dla dwóch plików
komentarz 14 kwietnia 2018 przez draghan VIP (106,230 p.)

Nie lepiej bez kontenera vector? Tworzenie funkcji getWords/stringToInt strasznie wszystko komplikuje.

To rozwiązanie jest w porządku, czemu uważasz że wszystko komplikuje?

komentarz 15 kwietnia 2018 przez niezalogowany

draghan Rozwiązanie da się ukrócić o 2/3 kodu. Usunąć można vector, atoi, c_str, vector::at, getline. Naprawdę kopiowanie vectora 3000 stringów do vectora 3000 intów było potrzebne? 

int main()
{
	std::ifstream words("Words.txt"), keys("Keys.txt");
	std::ofstream decoded("wyniki_6_2.txt");
	
	if (words.is_open() && keys.is_open())
	{
		std::string word;
		int key;
		while (words >> word && keys >> key)
		{
			decoded << decryption(word, key) << "\n";
		}
	}
}

Krócej, przejrzyściej przy zachowaniu tej samej funkcjonalności. 

Krzysiu Czereczon 

Tak właściwie sam doprowadziłeś sobie do takiej redundancji. Rozdzielanie pliku na dwa różne nie miało sensu, bo w zadaniu jasno podali jak plik ma wyglądać. Samo CKE przyznało się do błędu i rozwiązało ten problem następująco - plik wejściowy ma być sprawdzany do 700 linii (zanim pojawiłyby się dane niezgodne z treścią zadania). 

1 odpowiedź

+2 głosów
odpowiedź 15 kwietnia 2018 przez mokrowski Mędrzec (156,260 p.)
wybrane 15 kwietnia 2018 przez Krzysiu Czereczon
 
Najlepsza

A nie lepiej tak?

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstdlib>

// Szyfr Cezara na: 'A' <-> 'Z'
std::string decode(const std::string& word, int key) {
    constexpr static int alpha_diff = 'Z' - 'A' + 1;
    std::string result;
    result.reserve(word.size()); // Przy znanej wielkości wyniku, unikam realokacji pamięci
    for(const char letter: word) {
        result += (letter - (key % alpha_diff) + 'A') % alpha_diff + 'A';
    }
    return result;
}

int main() {
    std::ifstream words("dane_6_2.txt");
    std::ofstream results("wyniki_6_2.txt");
    std::string line;
    std::string word;
    std::string key;
    std::stringstream ss;

    if(!words || !results) {
        std::cerr << "Błąd otwarcia plików!\n";
        exit(EXIT_FAILURE);
    }

    // Czytanie linia po linii
    while(std::getline(words, line)) {
        ss.str(line);
        // Rozbicie na słowo i klucz
        ss >> word >> key; 
        results << (ss ? decode(word, std::stoi(key)): "ERROR!!") << '\n';
        ss.clear(); // Czyszczenie stanu strumienia
    }
    return EXIT_SUCCESS;
}

 

komentarz 15 kwietnia 2018 przez Krzysiu Czereczon Nowicjusz (170 p.)
również dobre

Podobne pytania

0 głosów
0 odpowiedzi 5,670 wizyt
+2 głosów
3 odpowiedzi 3,177 wizyt
pytanie zadane 13 czerwca 2016 w C i C++ przez xandros Nałogowiec (29,450 p.)

93,028 zapytań

141,991 odpowiedzi

321,294 komentarzy

62,375 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Wprowadzenie do ITsec, tom 2

Można już zamawiać tom 2 książki "Wprowadzenie do bezpieczeństwa IT" - będzie to około 650 stron wiedzy o ITsec (17 rozdziałów, 14 autorów, kolorowy druk).

Planowana premiera: 30.09.2024, zaś planowana wysyłka nastąpi w drugim tygodniu października 2024.

Warto preorderować, tym bardziej, iż mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy dodatkowe 15% zniżki! Dziękujemy zaprzyjaźnionej ekipie Sekuraka za kod dla naszej Społeczności!

...