Kwadraty steganograficzne


14

Kwadraty steganograficzne

Twoim zadaniem jest pobranie ciągu i wygenerowanie NxNobrazu reprezentującego ten ciąg. Musisz także napisać algorytm, który pobiera obraz i przekształca go z powrotem w ciąg znaków. Punktacja będzie obejmować liczbę bajtów obu algorytmów:

Algorytm „szyfrowania” + algorytm „deszyfrowania” .

Powinieneś wysłać każdy osobno, z liczbą bajtów dla algorytmów szyfrowania i deszyfrowania wyświetlanych osobno.


Przykładowy algorytm

Na przykład oto „Programowanie zagadek i golfa kodowego” przy użyciu prostego algorytmu steganograficznego opartego na ASCII w kanale Blue:

#2e7250,#6ea972,#04eb6f,#0fc767,#74ab72,#ee6161
#b73b6d,#1aae6d,#f37169,#bda56e,#1fe367,#e99620
#706450,#0d3575,#146b7a,#4ea47a,#2a856c,#95d065
#3f2d73,#cef720,#bab661,#d1b86e,#f22564,#12b820
#0f3d43,#c86e6f,#1ee864,#a66565,#247c20,#c3bb47
#0e296f,#89d46c,#585b66,#c08f20,#455c20,#136f20

Rzeczywisty obraz ( Obraz wygenerowany przez algorytm.)

Obraz wysadzony w powietrze.

Możesz zobaczyć, że niebieski kanał po prostu przechowuje wartości ascii dla tego obrazu:

50 =  80(P) 72 = 114(r) 6f = 111(o) 67 = 103(g) 72 = 114(r) 61 =  97(a) 
6d = 109(m) 6d = 109(m) 69 = 105(i) 6e = 110(n) 67 = 103(g) 20 =  32( ) 
50 =  80(P) 75 = 117(u) 7a = 122(z) 7a = 122(z) 6c = 108(l) 65 = 101(e) 
73 = 115(s) 20 =  32( ) 61 =  97(a) 6e = 110(n) 64 = 100(d) 20 =  32( ) 
43 =  67(C) 6f = 111(o) 64 = 100(d) 65 = 101(e) 20 =  32( ) 47 =  71(G) 
6f = 111(o) 6c = 108(l) 66 = 102(f) 20 =  32( ) 20 =  32( ) 20 =  32( )

Podczas gdy pozostałe kanały przechowują losowo generowane wartości, aby „urozmaicić” różnorodność kolorów na obrazie. Wyciągając wiadomość z obrazu, możemy po prostu zignorować inne wartości kanału i wyciągnąć bit szesnastkowy z niebieskiego kanału, rekonstruując ciąg:

"Programming Puzzles and Code Golf"

Zwróć uwagę, że spacje użyte do wypełnienia łańcucha w kwadracie nie są uwzględniane w końcowym odszyfrowanym wyjściu. Chociaż musisz wstawić ciąg znaków na obrazie, możesz założyć, że ciąg wejściowy nie będzie kończył się spacjami.


Zasady

  • Musisz zakodować 1 znak na piksel, kanał wybrany do zakodowania znaku jest dowolny.
  • Kanały pozostałych kolorów RGB muszą być losowe, inne niż ten, w którym chcesz zakodować ciąg; oznacza to, że Twoje ostateczne niekodowane kanały musiałyby znajdować się pomiędzy 0x0000-0xFFFF(losowo wybrane).
  • Wyrażenie końcowego wyniku jako tablicy 2D wartości kolorów RGB jest w porządku 0x000000-0xFFFFFF, nie trzeba używać tworzenia obrazu, chyba że chcesz się dobrze bawić lub jeśli jest mniej bajtów. Jeśli wybierzesz wyjście jako ciągi szesnastkowe, poprzedź ciąg szesnastkowy za pomocą #EG #FFFFFFlub #05AB1E. Możesz oddzielić tabulatory, przecinki lub cokolwiek innego, co byłoby rozsądne w poziomie, ale musi zachować kwadratowy wzór; innymi słowy, musisz zastosować odpowiednią separację nowego wiersza.
  • Dane wyjściowe muszą być w kwadracie, a łańcuch musi być wypełniony spacjami na końcu, aby to uwzględnić. To znaczy że N≈SQRT(Input#Length()). Jeśli długość wejściowa nie jest idealnym kwadratem, należy zaokrąglić w górę Ni wstawić spacje.
  • Jak wspomniano wcześniej, jeśli wypełniasz spacje obrazem, nie możesz umieszczać znaków dopełnianych na końcowym wyjściu „odszyfrowanym”.
  • Możesz założyć, że:
    • Łańcuch wejściowy nie kończy się spacjami.
    • Łańcuch wejściowy będzie używał tylko drukowalnych znaków ASCII.
  • To jest , wygrywa najmniej bajtów.

Żeby wyjaśnić, rozwiązania muszą kodować / dekodować dokładnie jeden znak na piksel?
ETHprodukcje

@ETHproductions, które brzmi jak dobre wyzwanie, ale dla celów tego konkursu wybierasz kanał kodowania i kodujesz 1 znak na piksel.
Magic Octopus Urn

Prawdopodobnie nie zamierzam tego używać, ale: czy można „nakładać” obraz z większą ilością miejsca niż to konieczne? I czy można założyć, że obraz będzie miał taką samą ilość nakładek, jak w przypadku kodera?

@ ais523 Nie widzę, jak to podejście mogłoby zrobić cokolwiek, ale wymaga więcej bajtów do wdrożenia. Idę z „nie”, ponieważ wyzwanie jest za stare, aby dokonywać takich dużych zmian.
Magic Octopus Urn

1
Racja, nie byłem pewien, czy było to dozwolone w pierwotnym pytaniu, zamiast zalecać zmianę. (Myślałem o spakowaniu danych wejściowych do prostokąta, który ma łatwiejsze, a zatem być może krótsze bajtowo obliczenia współrzędnych niż upakowanie go w kwadracie, a następnie wypełnienie prostokąta większym kwadratem.)

Odpowiedzi:


2

05AB1E , 34 + 12 = 46 bajtów

Wykorzystuje czerwony kanał.
05AB1E używa CP-1252 kodowanie .

Kodować:

DgDtî©n-Äð×JvyÇh`4F15Ý.Rh«}})'#ì®ä

D                                   # duplicate input
 gDtî©n-Ä                           # abs(len(input)-round_up(sqrt(len(input)))^2)
         ð×J                        # join that many spaces to end of input
            v                       # for each char in string
             yÇ                     # get ascii value
               h`                   # convert to base-16 number
                 4F                 # 4 times do:
                   15Ý.Rh           # push random base-16 number
                         «          # concatenate
                          }}        # end inner and outer loop
                            )       # wrap in list
                             '#ì    # prepend a "#" to each element in list
                                ®ä  # split in pieces round_up(sqrt(len(input))) long

Wypróbuj online!

Rozszyfrować:

˜vy3£¦HçJ}ðÜ

˜               # deep flatten input to a list
 v              # for each color in the list
  y3£           # take the first 3 chars
     ¦          # remove the hash sign
      H         # convert from base-16 to base-10
       ç        # get the ascii char with that value
        J       # join to string
         }      # end loop
          ðÜ    # remove trailing spaces

Wypróbuj online!

Alternatywna metoda wypełniania z jednakową liczbą bajtów

Dgð×J¹gtî©n£

Myślę, że musisz specjalnie dołączyć do nowych linii, zgodnie z pytaniem? (Twoja odpowiedź najprawdopodobniej pobije moją, nawet jeśli jest do tego przystosowana, ponieważ spędziłem tylko pięć bajtów, zajmując się tą częścią pytania, i masz o wiele więcej.)

@ ais523: Reguły mówią, że tablice 2D były w porządku. Czy jakoś źle to zrozumiałem?
Emigna,

„Możesz rozdzielać tabulatory, przecinki lub cokolwiek innego, co byłoby rozsądne w poziomie, ale musi zachować kwadratowy wzór; innymi słowy, musisz zastosować odpowiednią separację nowego wiersza”. zdecydowanie sugeruje, że musi to być ciąg, ponieważ tablice 2D z natury nie zawierają znaków nowej linii. Innymi słowy, interpretowałem „tablicę” jako opisującą kształt danych wyjściowych, a nie typ danych wyjściowych.

@ ais523: Poprosiłem OP o wyjaśnienia. Jak mówisz, nie jest to duża zmiana do zaimplementowania, ale być może możesz również zapisać niektóre bajty, jeśli formatowanie nie jest potrzebne.
Emigna,

@ ais523 w obu przypadkach jest akceptowalny.
Magic Octopus Urn

4

C, 201 (kodowanie) + 175 (dekodowanie) = 376 bajtów

Aby zakodować:

E(char*J){size_t L=ceil(sqrt(strlen(J)));int U;srand(time(NULL));for(int i=0;i<L;i++){for(int f=0;f<L;f++){printf("#%02X%02X%02X ",rand()%256,(U<strlen(J))?(int)J[U]:32,rand()%256);U+=1;}printf("\n");}}

Koduje każdy znak ciągu wejściowego w zielonym kanale widma RGB, jednocześnie ustawiając dwa pozostałe kanały jako losowe wartości szesnastkowe. Pobiera dane wejściowe przez STDIN jako ciąg znaków i wysyła do STDOUT ciąg wielu linii szesnastkowego kodu koloru w kształcie kwadratu. Zakładając, że masz zainstalowany Python 3 i ImageMagick, a powyższy plik jest kompilowany do pliku o nazwie a.outw bieżącym katalogu roboczym (CWD), możesz bezpośrednio uzyskać obraz wynikowy o nazwie Output.png, do CWD z tekstu wyjściowego za pomocą następującego polecenia:

./a.out "<Multiline Input>"|python3 -c "import sys,subprocess;Input=sys.stdin.read();print('# ImageMagick pixel enumeration: {0},{0},255,rgb\n'.format(len(Input.split('\n')[1].split()))+'\n'.join(['%d,%d:(%d,%d,%d)'%(g,i,int(j[1:][:2],16),int(j[1:][2:4],16),int(j[1:][4:6],16))for g,h in enumerate(Input.split('\n'))for i,j in enumerate(h.split())]))"|convert - -scale 1000% Output.png

Oto przykładowy obraz wyjściowy utworzony przez powyższą komendę Programming Puzzles and Code Golfjako ciąg wejściowy:

Przykładowe dane wyjściowe

Aby zdekodować:

D(int c,char**U){char T[c];for(int Y=1;Y<c;Y++){char G[2]={U[Y][3],U[Y][4]};T[Y-1]=(char)strtol(G,NULL,16);}int C=c-1;T[C]='\0';while(T[C]==' '){T[C]='\0';C-=1;}printf("%s\n",T);}

Pobiera dane wejściowe przez STDIN sekwencję rozdzielonych spacjami ciągów znaków w kolorze heksadecymalnym, z których każdy jest zamknięty w podwójnych cudzysłowach ( ") ( char** argvin main), a także po wywołaniu w main,int argc dla wprowadzania liczb całkowitych. Wysyła do STDOUT ciąg jedno- / wieloliniowy reprezentujący zdekodowany komunikat.

Z czasem spróbuję zagrać w golfa, kiedykolwiek i gdziekolwiek będę mógł.


Ponadto, jeśli obie metody są takie same w tym samym pliku, można użyć następującej mainmetody, aby połączyć wszystko z każdą funkcją otrzymującą prawidłowe dane wejściowe:

int main(int argc,char**argv){if(strcmp(argv[1],"E")==0){Encode(argv[2]);}else{Decode(argc,argv);}}

i używając tego, do kodowania musisz podać Ejako pierwszy argument wywołujący metodę kodowania, a następnie argument o pojedynczym ciągu, podczas gdy do dekodowania wystarczy podać sekwencję rozdzielonych spacjami ciągów kodu koloru szesnastkowego z każdym z nich zamkniętym w podwójne cudzysłowy (" ).


Wreszcie, jeśli chcesz, możesz uzyskać w pełni przygotowaną, gotową do użycia wersję tutaj , chociaż nie jest golfa, ale także nie wyświetla żadnych ostrzeżeń ani błędów po kompilacji.


3

Python 2, 164 160 + 94 93 = 253 bajtów

Oszczędność 1 + 1 bajtu dzięki Kreatorowi pszenicy.

-5 bajtów dzięki Kade

Obraz enkoderaKoder: ciąg musi być ujęty w cudzysłów, np. "CodeGolf"Wyjście jest kolorowym obrazem PPC ascii.

from random import*
s=input()
n=int((len(s)-1)**0.5)+1
s=s.ljust(n*n)
r=randint
print"P3 %d %d 255 "%(n,n)+''.join("%d "*3%(r(0,255),r(0,255),ord(c))for c in s)

Obraz dekoderaDekoder: Pobiera wejściową nazwę pliku jako argument wiersza poleceń

from sys import*
print''.join(chr(int(c))for c in open(argv[1]).read().split()[6::3]).strip()

Stosowanie:

 python golf_stegansquare_enc.py > stega.ppm

 python golf_stegansquare_dec.py stega.ppm

Przykład:

Programowanie zagadek i Code GolfProgramowanie zagadek i Code Golf

Lorem IpsumLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.


Możesz usunąć odstęp między zamkniętym paren, a następniefor
Post Rock Garf Hunter

@ETHproductions: sqrt (25-1) = sqrt (24) <5 i> 4. intz tego jest 4, które jest następnie +1edytowane, więc 5
Karl Napf

O mój Boże, nie widziałem -1.
ETHprodukcje

1
Można usunąć przestrzeń pomiędzy printi 'w dekoderze. Jestem też całkiem pewien, że możesz zrobić, int((len(s)+1)**.5)aby zaoszczędzić trochę bajtów.
Kade,

1
Redaguję ostatnie zdanie mojego poprzedniego komentarza, jednak możesz skrócić drukowanie, zmieniając ' '.join("%d %d %d"na, ''.join(3*"%d "ponieważ jestem pewien, że końcowe miejsce jest OK.
Kade,

2

Scala, 97 + 68 = 165 bajtów

Szyfrowanie (97 bajtów):

s=>s.map(_+((math.random*65535).toInt<<8)).iterator.grouped(math.sqrt(s.size)toInt)withPadding 32

Bierze ciąg i ponownie stroi iterator sekwencji liczb całkowitych.

Deszyfrowanie (68 bajtów):

a=>" +$".r.replaceAllIn(a.flatten.map(h=>(h&0xFF)toChar)mkString,"")

Pobiera iterator sekwencji liczb całkowitych i zwraca ciąg znaków.

Wyjaśnienie:

s=>                         //define an anonymous function
  s.map(                      //map each char of the string
    _+(                         //to the ascii value plus
      (math.random*65535).toInt)  //a random integer between 0 and 65535
      <<8                         //shifted 8 bits to the left
    )
  )
  .iterator                     //create an iterator
  .grouped(                     //group them in groups of size...
    math.sqrt(s.size)toInt        //sqrt of the size of the input, rounded up
  )withPadding 32               //pad with spaces to make a square

.

a=>
  " +$"              //take this string
  .r                 //parse it as a regex
  .replaceAllIn(     //replace every occurence of the regex in...
    a.flatten          //a flattened
    .map(h=>           //each element mapped
      (h&0xFF)toChar)    //to the character of the lower 8 bits
    mkString,          //joined to a string
    ""               //with an empty string
  )

2

Perl, (103 + 1) + (36 + 2) = 142 bajty

Koder tekstu na obraz (uruchamiany z -pkarą 1-bajtową; -p0(dodatkowy bajt kar) jest konieczny, jeśli chcesz obsługiwać znaki nowej linii w ciągu wejściowym):

$_.=$"while($a=(length)**.5)=~/\./;$_=unpack"H*";s/../sprintf"#%04x$&,",rand+4**8/eg;s/(.*?\K,){$a}/
/g

Dekoder obrazu do tekstu (uruchamiany z -p0karą 2-bajtową):

$\.=chr hex for/..\W/g;$\=~s/ *$//}{

Używa #abcdeftekstowego formatu obrazu i koduje w niebieskim kanale. Oto przykład możliwego wyniku podanego Programming Puzzles and Code Golfjako dane wejściowe:

# b4d250, # bccb72, # 43f06f, # 4d6767, # 74ba72, # 269461
# e4f26d, # f63d6d, # 701c69, # bbf56e, # 6ef967, # d78d20
# 4e0d50, # 9b2775, # afd37a, # 12a47a, # 63e46c, # 0e9565
# 4cad73, # e43420, # 6da761, # 5a306e, # 8fba64, # 58f720
# d52443, # b4446f, # fbaf64, # 4a4365, # 1a5020, # f3ea47
# 354c6f, # 52cb6c, # 11a766, # 4c380a, # 553820, # b31120

Objaśnienie enkodera:

$_.=$"             # append a space ($") to the input ($_)
  while            # as long as the following condition holds:
(($a=length)**.5)  # the square root of the input length (save this in $a)
=~/\./;            # has no decimal points in its string represenation
$_=unpack"H*";     # convert the input from base-256 to hexadecimal
s/../              # replace two characters of the input
  sprintf          # with a string formed from the template
  "#%04x$&,",      # four hex digits, the two matched characters, and a comma
  rand+4**8        # those hex digits are a random number from 0 to 4**8 (= 65536)
/eg;               # and do this for every non-overlapping match
s/(.*?             # find the minimum number of characters needed to match
   \K,)            # replacing the part of the match after the last matched comma
  {$a}/            # a string containing $a commas
/gx                # with a newline, for every non-overlapping match

Byłem bardzo zadowolony z tego zastosowania \K; określa miejsce zamiany i umieszczenie go w pętli wydaje się, że liczy się wystąpienie ostatniej iteracji w pętli. Dopasuje więc s/(.*?\K,){$a}/\n/gciąg o minimalnej długości w postaci cokolwiek przecinek cokolwiek przecinek… cokolwiek przecinek, który ma $aprzecinki, ale faktycznie zastąpiona część dopasowania będzie po prostu ostatnim przecinkiem. Powoduje to zastąpienie każdego $aprzecinka nową linią, co daje nam kwadratowy kształt obrazu.

Dużą zaletą Perla do tego wyzwania (innego niż wbudowany konwerter znaków na szesnastkowy, który był niezwykle wygodny) jest to, że ma bardzo krótki dekoder (tak krótki, że chociaż Perl ma wbudowaną funkcję konwertując szesnastkowy na ciąg, krócej było go nie używać). Oto jak to działa:

$\.=chr      # append to $\ the character code
  hex        # of the hexadecimal-string-to-number-translation
for/..\W/g;  # of each two characters that appear before a
             # non-alphanumeric character (not counting overlapping matches)
$\=~s/ *$//  # delete all spaces at the end of $\
}{           # in this context, this means "implicitly print $\,
             # prevent any other implicit printing"

Jedynymi przypadkami dwóch znaków bezpośrednio przed znakiem niealfanumerycznym są niebieskie kanały (które chcemy rozpakować), które pojawiają się tuż przed przecinkami i znakami nowej linii; oraz dwie postacie, które pojawiają się przed sobą #niż pierwsza. Nie chcemy drugiej kategorii meczów, ale nieuchronnie pokrywają się z poprzednią kategorią, a zatem zostaną wykluczone przez kontrolę nakładających się meczów.


1

MySQL, 438 + 237 = 675 bajtów

Na końcu danych wyjściowych znajduje się nowy wiersz, ale nie pojawia się on po odszyfrowaniu. Funkcja szesnastkowa (przeciążenie liczb całkowitych) odetnie wiodące zera, więc musiałem uzupełnić ją ciągiem 0. Mogłem zapisać niektóre bajty, gdybym mógł zadeklarować obie funkcje między ogranicznikami.

Szyfruj

delimiter //create function a(i text)returns text begin declare r int;declare q,p text;while mod(length(i),sqrt(length(i)))<>0 do set i:=concat(i,' ');end while;set r:=1;set q:="";while r<=length(i) do set p:=",";if mod(r,sqrt(length(i)))=0 then set p:="\r\n";end if;set q:=concat(q,'#',right(concat(0,hex(floor(rand()*256))),2),right(concat(0,hex(floor(rand()*256))),2),hex(mid(i,r,1)),p);set r:=r+1;end while;return q;end//
delimiter ;

Odszyfruj

delimiter //create function b(i text)returns text begin declare x int;declare y text;set x:=0;set y:="";while instr(i,'#')>0 do set i:=substr(i,instr(i,'#')+5);set y:=concat(y,unhex(left(i,2)));end while;return trim(y);end//
delimiter ;

Stosowanie:

select a('test')
select b('#7D1874,#FFB465')
select b(a('test'))

1

C #, 312 + 142 = 454 bajtów

Kodowanie:

using System;I=>{var r=new Random();int i=I.Length;int N=(int)Math.Floor(Math.Sqrt(i))+1,S=N*N;while(i++<S){I+=' ';}var R="";for(i=0;i<S;){R+=i%N<1&i>0?"\n":i<1?"":" ";R+="#"+r.Next(256).ToString("X").PadLeft(2,'0')+r.Next(256).ToString("X").PadLeft(2,'0')+((int)I[i++]).ToString("X").PadLeft(2,'0');}return R;};

Rozszyfrowanie:

using System;I=>{var s=I.Replace('\n',' ').Split(' ');var R="";foreach(var t in s)R+=(char)System.Convert.ToInt32(t[5]+""+t[6],16);return R.TrimEnd(' ');};

Pełny program:

using System;
class Steganographic
{
    static void Main()
    {
        Func<string, string> E = null;
        Func<string, string> D = null;

        E=I=>
        {
            var r=new Random();
            int i=I.Length;
            int N=(int)Math.Floor(Math.Sqrt(i))+1,S=N*N;
            while(i++<S){I+=' ';}
            var R="";
            for(i=0;i<S;)
            {
                R+=i%N<1&i>0?"\n":i<1?"":" ";
                R+="#"+r.Next(256).ToString("X").PadLeft(2,'0')+r.Next(256).ToString("X").PadLeft(2,'0')+((int)I[i++]).ToString("X").PadLeft(2,'0');
            }
            return R;
        };

        D=I=>
        {
            var s=I.Replace('\n',' ').Split(' ');
            var R="";
            foreach(var t in s)
                R+=(char)Convert.ToInt32(t[5]+""+t[6],16);
            return R.TrimEnd(' ');
        };

        string encoded = E("Programming Puzzles and Code Golf");
        Console.WriteLine(encoded);
        Console.WriteLine(D(encoded));

        encoded = E("Hello, World!");
        Console.WriteLine(encoded);
        Console.WriteLine(D(encoded));

        Console.Read(); // For Visual Studio
    }
}

1

Mathematica, 111 + 65 = 176 bajtów

Enkoder

Join[255~RandomInteger~{n=⌈Sqrt@Length@#⌉,n,2},ArrayReshape[#,{n,n,1},32],3]~Image~"Byte"&@*ToCharacterCode

Dekoder

StringTrim[""<>FromCharacterCode@ImageData[#,"Byte"][[;;,;;,3]]]&

1

Przetwarzanie, 220 209 194 + 171 167 151 = 391 380 376 361 345 bajtów

Aktualizacja:

Usunięto bezużyteczne noStroke()i uczyniono jedno-wyciągowe dla obu pętli for.

Usunięty bezużyteczny image(p,0,0);, podał deszyfratorowi nazwę pliku jako parametr

Algorytm szyfrowania

void g(String h){int s=ceil(sqrt(h.length()));for(int y=0,x;y<s;y++)for(x=0;x<s;rect(x,y,1,1),x++)stroke(h.length()>y*s+x?h.charAt(y*s+x):32,random(255),random(255));get(0,0,s,s).save("t.png");}

Wywołanie funkcji: g("Programming Puzzles and Code Golf");

Jest to funkcja, która pobiera ciąg znaków i tworzy wynik przed zapisaniem go jako t.png. Wykorzystuje redwartość do przechowywania ukrytego tekstu.

Algorytm deszyfrowania

void u(String f){PImage p=loadImage(f);f="";for(int j=0,i;j<p.height;j++)for(i=0;i<p.width;i++)f+=(char)red(p.get(i,j));print(f.replaceAll(" +$",""));}

Funkcja wywołania przez: u(file_name);

Jest to również funkcja, która wyszukuje obraz określony przez parametr, a następnie wyświetla ukryty ciąg (ponieważ jest krótszy niż zwracanie ciągu).

Rozszerzony kod

(Algorytm szyfrowania)

void g(String h) {
  int s=ceil(sqrt(h.length()));
  for(int y=0,x;y<s;y++)
    for(x=0;x<s;rect(x,y,1,1),x++)
      stroke(h.length()>y*s+x?h.charAt(y*s+x):32,random(255),random(255));
  get(0,0,s,s).save("t.png");
}

Ciąg jest przekazywany po wywołaniu funkcji. Pierwszy wiersz funkcji oblicza długość boku kwadratu, biorąc ceilpierwiastek kwadratowy. Następnie wchodzimy do pętli for, w której ustawiamy stroke(kolor krawędzi), aby wartość ASCII znaku była czerwona, a losowe wartości dla niebieskiego i zielonego. Po wykonaniu tej czynności tworzymy rect(prostokąt) o szerokości = 1i wysokości = 1, tj. Pikselu (z jakiegoś dziwnego powodu nie mogę pointprawidłowo użyć ). W ostatnim wierszu powstały obraz jest następnie zapisywany jako t.png.

(Algorytm deszyfrowania)

void u(String f) {
  PImage p=loadImage(f);
  f="";
  for(int j=0,i;j<p.height;j++)
    for(i=0;i<p.width;i++)
      f+=(char)red(p.get(i,j));
  print(f.replaceAll(" +$",""));
}

Ta funkcja ma nazwę pliku jako parametr (jako ciąg znaków). Następnie obraz w pliku jest przechowywany w zmiennej do późniejszego wykorzystania. Po zakończeniu tej czynności ustawiamy ciąg na ""zamiast tworzyć nowy ciąg tylko po to, aby zatrzymać ukryty ciąg. Następnie iterujemy obraz za pomocą dwóch zagnieżdżonych pętli for i dodajemy do łańcucha wartość znakową czerwonej wartości piksela. Na koniec drukujemy powstały ciąg po usunięciu z niego spacji wiodących (za pomocą wyrażenia regularnego). Powodem, dla którego drukujemy ukryty tekst zamiast go zwracać, jest to, że w ten sposób jest on krótszy i oszczędzamy bajty.


Zaszyfrowany surowy tekst wyzwania:

wprowadź opis zdjęcia tutaj


1

Galaretka, 40 + 20 = 60 bajtów na stronie kodowej Jelly

Koder (tekst → obraz):

”#;;ØHX¤¥4¡
»⁶x⁹²¤¤Ob⁴‘ịØHÇ€sj€”,Y
L½Ċç@

Wypróbuj online!

Dekoder (obraz → tekst):

ḣ2ØHiЀ’ḅ⁴Ọ
ṣ”#Ç€œr⁶

Wypróbuj online!

Przykładowe dane wyjściowe, które program może wygenerować (przechowuje informacje w czerwonym kanale):

#504219,#720200,#6F38F1,#67055F,#7228C7,#61AC95
#6DD797,#6D20CB,#6962FA,#6E69B1,#67C41C,#209436
#50CB19,#75C9FC,#7A1B06,#7A695B,#6C5D5B,#6539A6
#735925,#20C80F,#612C38,#6EBF9E,#64C79E,#200915
#4337C5,#6F4704,#64FB5F,#65B2D1,#20E075,#47BC7C
#6F0C16,#6CD8EF,#66060B,#203C6C,#20D6E9,#20C0D7

W tych większych wyzwaniach zwięzłość Jelly zaczyna nieco opadać, potrzebując kilku postaci „strukturalnych”, aby rozwiązać dwuznaczności parsowania, ale mimo to jest bardzo zwięzła. Oto jak działa koder:

Subroutine 1: convert digits to randomly padded hex string
”#;;ØHX¤¥4¡
”#;                     prepend #
    ØHX                 random hexadecimal digit
       ¤                parse ØH and X as a unit
   ;                    append
        ¥               parse ; and ØHX¤ as a unit
         4¡             repeat four times

Subroutine 2: convert string λ to square with size ρ
»⁶x⁹²¤¤Ob⁴‘ịØHÇ€sj€”,Y
 ⁶                      space
   ⁹²                   ρ squared
     ¤                  parse ⁹² as a unit
  x                     repeat string (i.e. ρ² spaces)
      ¤                 parse ⁶x⁹²¤ as a unit
»                       take maximum
Because space has the lowest value of any printable ASCII character,
this has the effect of padding λ to length ρ² with spaces.
       O                take codepoints of string
        b⁴              convert to base 16
           ịØH          use as indexes into a list of hexadecimal digits
          ‘             0-indexed (Jelly uses 1-indexing by default)
              ǀ        run subroutine 1 on each element
                s       split into groups of size ρ
                  €     inside each group
                 j ”,   join on commas
                     Y  join on newlines

Main program: basically just calculates ρ and lets subroutine 2 do the work
L½Ċç@
L                       length of input
 ½                      square rooted
  Ċ                     rounded up to the next highest integer
   ç@                   call subroutine 2 with the original input and the above

A oto jak działa dekoder:

Subroutine: convert hexadecimal color string (without #) to character
ḣ2ØHiЀ’ḅ⁴Ọ
ḣ2                      take first two characters
  ØHi                   find indexes in a string of hexadecimal digits
     Ѐ                 for each of those characters
       ’                0-indexed (Jelly uses 1-indexing by default)
        ḅ⁴              convert from base 16
          Ọ             convert integer to character

Main program:
ṣ”#Ç€œr⁶
ṣ”#                     split on # signs
   ǀ                   run the subroutine for each element
     œr⁶                remove spaces from the right
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.