No dobra... skrocilem kod...
dokladnie 'pare linii' tak jak przewidzialem.
Co prawda nie podalem zadnych ladnych komunikatow itd ale kod dziala... wiec policzylem ile bylo linii w oryginalnym kodzie mtbs'a a ile jest w moim... 2 funkcje z oryginalnego kodu skrocilem z 53 linii do 1 dokladnie... a wywalajac linie puste i pomijajac banery itd, skrocilem calosc ze 115 do 9 linii.
Zasada dzialania
Doszedlem do wniosku, ze definiowanie IF'ow i sztywne kodowanie translacji to tylko strata czasu i znaczne zuzycie przyciskow Ctrl, C oraz V
Postanowilem generowac sobie takie polecenie w locie, dla dowolnego przesuniecia.
Opisalem wiec jakie litery sa dopuszczalne - jest to dopuszczalny alfabet wiadomosci - zostawilem domyslnie male litery alfabetu i to do tego nie kompletne (jest 24 a powinno byc 26, brakuje v oraz q ale zrobilem kopiuj-wklej z kodu mtbs'a aby zachowac max zgodnosc wynikow).
Tak wiec zadanie to wygenerowac w locie tekst przesuniety o N w prawo, poniewaz przesuniecie w lewo nas nie interesuje w ogole (a dlaczego wyjasnie dalej). Tak wiec do kodu...
Wersja 1
Kod:
my $valid_chars = 'abcdefghijklmnoperstuwxyz';
my @chars = $valid_chars =~ /./g;
sub przesuniecie {
my $subst;
for (0 .. $#chars-1) {
$subst .= $chars[($_+$_[0])%$#chars];
}
return $subst;
}
print przesuniecie(3); # zwraca: defg...xyabc
Najpierw okreslamy sobie dopuszczalny alfabet, pozniej dzielimy to sobie na tablice. Funkcja przesuwajaca leci w petli po calej dlugosci tablicy od 0 do $#tablica czyli najwyzszego numeru elementu w tablicy. Trzeba go jednak pomniejszyc o 1 bo dalej w obliczeniach wychodzi wesolo :P
Glowny krok tej petli to dopisanie na koncu zmiennej $subst znaku znajdujacego sie w tablicy @chars na miejscu
Kod:
AktualnyNumerPrzebiegu + Przesuniecie mod DlugoscAlfabetu
Daje to tyle, ze idac w prawo po tablicy i dodajac przesuniecie w koncu wyjdziemy poza jej koniec, wiec modulo wraca nas na poczatek tablicy, mozemy tak lazic do oporu - moge podac przesuniecie 12345 i kod bedzie dzialal poprawnie.
Teraz czas skrocic nieco ten kod stosujac standardowe funkcje perla
Wersja 2
Kod:
sub przesuniecie2 {
return map { $chars[($_+$_[0])%$#chars] } (0 .. $#chars-1);
}
to samo co wyzej ale stosujac map... dla zwiekszajacego sie licznika wykonaj (doslownie) zwroc element tablicy o numerze <wyliczenia>. Jest tu pewna niescisloc dotyczaca co jest zwracane - skalar czy tablica... kto chce ten doczyta w dokumentacji - tak czy inaczej dziala i daje ten sam efekt co pierwszy kod. Po prostu return() tak jakby magicznie wie jakiego rodzaju zmiennej oczekuje funkcja ktora wywolala funkcje. Print oczekuje raczej skalara a nie tablicy, wiec dostalismy skalar. Roznice bedzie wyraznie widac w wersji koncowej.
No to teraz czas skrocic calosc jeszcze bardziej i sprawdzic czy dziala!
Wersja koncowa
Kod:
#!/usr/bin/perl
use strict;
my ($text, $shift, $cmd) = @ARGV;
my $valid_chars = 'abcdefghijklmnoperstuwxyz';
my @chars = $valid_chars =~ /./g;
my $moved = join '', map { $chars[($_+$shift)%$#chars] } (0 .. $#chars-1);
$_=$text;
$cmd =~ /s/i ? eval "tr/$valid_chars/$moved/" : eval "tr/$moved/$valid_chars/";
print;
Jak widzicie aby uzyskac skalar $moved musialem zrobic join() bo map() zwrocilo tablice, zupelnie odwrotnie do tego co w wersji 2. Kod chcialem skrocic jeszcze o 3 linie ale nie mam juz czasu siedziec nad tym. 30 minut to i tak dosc dlugo w sumie. Chodzi o to, ze tr() o ile robi interpolacje zmiennych we wzorcu to nie interpoluje zmiennych w podstawieniu. Jesli zrobilibysmy podstawienie aaa z przesunieciem w sumie dowolnym jako tr/$valid_chars/$moved/ to dostaniemy 'ooo' bo 'o' to 3 znak podstawienia (pierwszy to $, drugi m, itd).
Dlatego wlasnie text przypisuje do domyslnej zmiennej, jesli polecenie to 's' robie eval() polecenia ktore poskladalem jako poprawnie INTERPOLOWANY string... tr() bez parametrow robi operacje na $_ wlasnie, tak samo jak ostatnie print()
Ot tyle magii i przygody na dzisiaj. Wracam do pracy hihi...