Szyfr cezara polski spoj

0

Witam!
Robię zadanie http://pl.spoj.pl/problems/JSZYCER/ . Generalnie zrobiłem wszystko jak należy oprócz jednej rzeczy. W tym zadaniu może być kilka linijek tekstu. Tylko skąd ja mam widzieć czy jak ktoś przyciśnie enter to chce przejść do następnej linii czy zakończyć pisanie? Oto działający kod dla jednej linijki:

#include <cstdio>
#include <cstring>

int main()

{
    char cg[101];
    fgets(cg,101,stdin);
    int tab[40];
    int i, x;
    for(i=0;i<=strlen(cg)-2;i++)
    {
        switch (cg[i])
        {
            case 'A': tab[i]=1; break;
            case 'B': tab[i]=2; break;
            case 'C': tab[i]=3; break;
            case 'D': tab[i]=4; break;
            case 'E': tab[i]=5; break;
            case 'F': tab[i]=6; break;
            case 'G': tab[i]=7; break;
            case 'H': tab[i]=8; break;
            case 'I': tab[i]=9; break;
            case 'J': tab[i]=10; break;
            case 'K': tab[i]=11; break;
            case 'L': tab[i]=12; break;
            case 'M': tab[i]=13; break;
            case 'N': tab[i]=14; break;
            case 'O': tab[i]=15; break;
            case 'P': tab[i]=16; break;
            case 'Q': tab[i]=17; break;
            case 'R': tab[i]=18; break;
            case 'S': tab[i]=19; break;
            case 'T': tab[i]=20; break;
            case 'U': tab[i]=21; break;
            case 'V': tab[i]=22; break;
            case 'W': tab[i]=23; break;
            case 'X': tab[i]=24; break;
            case 'Y': tab[i]=25; break;
            case 'Z': tab[i]=26; break;
            case ' ': tab[i]=27; break;
        }
    }
    for(i=0;i<=strlen(cg)-2;i++)
    {
        if (tab[i]==24)
        {
            tab[i]=1;
            x=1;
        }
        else if (tab[i]==25)
        {
            tab[i]=2;
            x=1;
        }
        else if (tab[i]==26)
        {
            tab[i]=3;
            x=1;
        }
        else if (x!=1)
            tab[i]+=3;
    }
    for(i=0;i<=strlen(cg)-2;i++)
    {
        switch (tab[i])
        {
            case 1: cg[i]='A'; break;
            case 2: cg[i]='B'; break;
            case 3: cg[i]='C'; break;
            case 4: cg[i]='D'; break;
            case 5: cg[i]='E'; break;
            case 6: cg[i]='F'; break;
            case 7: cg[i]='G'; break;
            case 8: cg[i]='H'; break;
            case 9: cg[i]='I'; break;
            case 10: cg[i]='J'; break;
            case 11: cg[i]='K'; break;
            case 12: cg[i]='L'; break;
            case 13: cg[i]='M'; break;
            case 14: cg[i]='N'; break;
            case 15: cg[i]='O'; break;
            case 16: cg[i]='P'; break;
            case 17: cg[i]='Q'; break;
            case 18: cg[i]='R'; break;
            case 19: cg[i]='S'; break;
            case 20: cg[i]='T'; break;
            case 21: cg[i]='U'; break;
            case 22: cg[i]='V'; break;
            case 23: cg[i]='W'; break;
            case 24: cg[i]='X'; break;
            case 25: cg[i]='Y'; break;
            case 26: cg[i]='Z'; break;
            case 27: cg[i]=' '; break;
        }
    }
    for(int j=0;j<=strlen(cg)-2;j++)
        printf("%c", cg[j]);
    return 0;
}

Z góry dzięki za pomoc.

PS Zauważyłem, że jednak nie wszystko jest dobrze. W niektórych przypadkach pojedyncze literki są w ogóle nie przekształcone.

0

to jest niewydajne. Po co zmieniasz najpierw na liczby a później przesuwasz to i na litery znowu?
http://pl.wikipedia.org/wiki/ASCII
więc robisz proste dwa ify

if (cg[i] >= 'A' && cg[i] <= 'W' ){
  cg[i] += 3 // z A zrobi D (kod ANSII  65 + 3 = 68 co da D
} else if ( cg[i] > 'W' && cg[i] <= 'Z') {
  cg[i] -= 22 // nie możemy dodać bo przekroczymy zakres ansii więc odejmujemy 22 (25-3);
} 

i zamiast tych 3 forów masz jeden
sądzę że pewnie to się da jeszcze lepiej napisać, ale mój kod wykona się i tak 3 razy szybciej niż Twój
Do tego czemu taka pętla?
for(i=0;i<=strlen(cg)-2;i++)
co to jest to magiczne -2?

Edit. a w ogóle, to nie musisz nawet zapisywać do cg[i] tylko po prostu od razu wyświetlać zwiększone o 3 (więc masz jedną pętle zamiast czterech)

0

Co do wczytywania danych, to zapoznaj się z http://pl.spoj.pl/forum/viewtopic.php?f=10&t=1207 (swoją drogą czemu nie ma tu znacznika url?). O tym jak ma wyglądać algorytm tego programu już ci widzę napisano.

0

zrób tak (szyfruj sam sobie napisz):

char buff[256];

while(fgets(buff, sizeof(buff), stdin)) {
     szyfruj(buff);
     puts(buff);
}
1

@fasadin - mnóstwo magicznych stałych w twoim kodzie, lepiej je ponazywać:

const char first = 'A';
const char last = 'Z';
const unsigned range = last - first + 1;
const unsigned offset = 3;

if (cg[i] >= first && cg[i] <= last - offset) {
  cg[i] += offset;
} else if (cg[i] > last - offset && cg[i] <= last) {
  cg[i] += offset - range;
}

A najlepiej sobie zrobić funkcję:

char Cezar(char ch, char range_first, char range_last, int offset)
{
    if (ch < range_first || ch > range_last) return ch;
    unsigned range = range_last - range_first + 1;
    return range_first + (unsigned)(ch - range_first + offset + range) % range;
}

// szyfrujemy
cg[i] = Cezar(cg[i], 'A', 'Z', 3);

// deszyfrujemy
cg[i] = Cezar(cg[i], 'A', 'Z', -3);
0
MrMatikm napisał(a):

... Tylko skąd ja mam widzieć czy jak ktoś przyciśnie enter to chce przejść do następnej linii czy zakończyć pisanie? ...

ha, nikt nie odpowiedział na najważniejsze (łącznie ze mną).

Niestety natura konsoli jest taka, że bez dodatkowych założeń (ostatnia linia jest pusta) nie da się stwierdzić kiedy jest koniec. Treść zadania nie określa dodatkowych warunków na koniec danych, więc zapomnij o konsoli.
Na SPOJ nikt jednak nie siedzi przy konsoli :), po prostu standardowe wejście jest przekierowane do pliku, wtedy stwierdzenie kiedy nastąpił koniec danych nie stanowi problemu.
Jeśli potrzebujesz testować swój program, to najlepiej przygotuj plik z danymi testowymi i wywołuj go przez:

JSZYCER <nazwaTwojegoPlikuZDanymi.txt

Jeśli korzystasz z IDE to na pewno znajdziesz opcję "program parameters", gdzie powinieneś wpisać: "<nazwaTwojegoPlikuZDanymi.txt" (plik powinien być w tym samym katalogu co plik wykonalny/miejsce uruchomienia programu).

0

Bardzo dziękuję za odpowiedzi.

Zrobiłem tak:

#include <cstdio>
#include <cstring>

int main()

{
    char cg[101];
    fgets(cg,101,stdin);
    int i;
    for(i=0;i<=strlen(cg)-2;i++)
    {
        if (cg[i]>='A' && cg[i]<='W')
            cg[i]+=3;
        else if (cg[i]>'W' && cg[i]<='Z')
            cg[i]-=23;
    }
    for(int j=0;j<=strlen(cg)-2;j++)
        printf("%c", cg[j]);
    return 0;
}

I wszystko działa. Jedyne czego nadal nie rozumiem to ta ilość linijek. Rozumiem, że coś z EOF, ale nie umiem tego zastosować. Chwilowo nie wiem dlaczego, ale SPOJ nie działa, ale jak zacznie działać to wejde w linka od sig i mam nadzieję, że się wyjaśni.

Do tego czemu taka pętla?
for(i=0;i<=strlen(cg)-2;i++)
co to jest to magiczne -2?

Musi być -2 bo ostatni znak ciągu to niepotrzebne mi 0, a tablica zaczyna się od 0 a nie 1.

PS Jakiego znacznika trzeba użyć żeby wpisany w poście użytkownik był "interaktywny"?

EDIT:
Spoj już działa. Przeczytałem tamtem post, ale nie do końca rozumiem:

#include<iostream>
using namespace std;
int main(void)
{
int x;
while(true)
{
cin>>x;
if(cin.eof())break; // albo if(cin.peek()==EOF)break;
// a w przypadku gdy szukamy np. entera: if(cin.peek()=='\n')break;
cout<<x<<endl;
}
}

Proszę o wytłumaczenie tego przykładu. Prosiłbym też o linka do jakiegoś kursu, gdzie jest wytłumaczone to nieszczęsne cin, bo dość często się pojawia, a ja nie wiem o co chodzi.

0

Podjąłem kolejną nieskuteczną próbę:

#include <cstdio>
#include <cstring>

int main()

{
    char cg[1001];
    char znak;
    while(~scanf("%c", &znak))
    {
    fgets(cg,1001,stdin);
    int i;
    for(i=0;i<=strlen(cg)-2;i++)
    {
        if (cg[i]>='A' && cg[i]<='W')
            cg[i]+=3;
        else if (cg[i]>'W' && cg[i]<='Z')
            cg[i]-=23;
    }
    if (znak>='A' && znak<='W')
        znak+=3;
    else if (znak>'W' && znak<='Z')
            znak-=23;
    printf("%c", znak);
    for(int j=0;j<=strlen(cg)-2;j++)
        printf("%c", cg[j]);
    return 0;
    }
}

Bardzo proszę o pomoc. Prosiłbym o napisanie jak to powinno być, bo zadanie wydaje się być proste oprócz tych niewiadomych linii.

0
void szyfruj(char slowo[])
{
    for(int i=0;i<strlen(slowo);i++)
    {
        if(!isspace(slowo[i]))
        {
            if(slowo[i]+3<='Z')slowo[i]=slowo[i]+3;
            else slowo[i] = 'A' + (slowo[i]+3)%'Z' - 1;
        }
    }
}

Czesc mojego rozwiazania... Za bardzo kombinujesz zamiast zrobic normalnie.

0

Tylko, że mi nie chodzi o samą zamianę literek. To już mam (najprostrsza wersja):

#include <cstdio>
#include <cstring>
 
int main()
 
{
    char cg[101];
    fgets(cg,101,stdin);
    int i;
    for(i=0;i<=strlen(cg)-2;i++)
    {
        if (cg[i]>='A' && cg[i]<='W')
            cg[i]+=3;
        else if (cg[i]>'W' && cg[i]<='Z')
            cg[i]-=23;
    }
    for(int j=0;j<=strlen(cg)-2;j++)
        printf("%c", cg[j]);
    return 0;
}

Chodzi mi o to jak zrobić, żeby wczytywał niewiadomą liczbę linii, a Twój kod (chyba) tego nie pokazuje.

0

Ludzie co wy macie z ta awersja do szukajek? Od tego sa... Wchodzisz na forum spoja i masz.

http://pl.spoj.pl/forum/viewtopic.php?f=10&t=1206

1 użytkowników online, w tym zalogowanych: 0, gości: 1