Szyfrowanie binarne

11

Jest to oparte na xkcd # 153 .

Utwórz program lub funkcję o nazwie, która pobierze 2 parametry, z których każdy jest łańcuchem, listą lub tablicą bajtów lub znaków. Drugi parametr będzie zawierał tylko znaki zaczerpnięte z lrfu(lub równoważne bajty ASCII). Należy to interpretować jako ciąg instrukcji do wykonania na sekwencji bitowej reprezentowanej przez pierwszy parametr.

Wykonane przetwarzanie musi być równoważne z następującymi:

  1. Konwertuj pierwszy parametr na pojedynczy ciąg bitów utworzony przez konkatenację bitów każdego znaku (interpretowanego jako jeden z 7-bitowego ASCII, 8-bitowego rozszerzonego ASCII lub standardowego kodowania Unicode). Np. Jeśli pierwszym parametrem jest, "AB"to będzie to jeden z 10000011000010(7-bitów), 0100000101000010(8-bitów lub UTF-8) 00000000010000010000000001000010lub 01000001000000000100001000000000(UTF-16 w dwóch endiannościach) itp.
  2. Dla każdego znaku w drugim parametrze wykonaj kolejno odpowiednią instrukcję:
    • lobraca łańcuch bitów w lewo. Np . 10000011000010Staje się 00000110000101.
    • robraca łańcuch bitów w prawo. Np . 10000011000010Staje się 01000001100001.
    • fodwraca (lub odwraca) każdy bit w łańcuchu bitów. Np . 10000011000010Staje się 01111100111101.
    • uodwraca ciąg bitów. Np . 10000011000010Staje się 01000011000001.
  3. Przekształć ciąg bitów na ciąg ASCII, który używa jednego znaku na bit. Np . 10000011000010Staje się "10000011000010". Wynika to z faktu, że nie wszystkie zestawy 7/8 bitów mają przypisany znak.

Przykład (w Pythonie):

>>> f("b", "rfu")
01110011

Przekształca się "b"w 8-bitową reprezentację binarną ASCII 01100010, obraca ją w prawo ( 00110001), odwraca każdy bit ( 11001110) i odwraca ( 01110011).

Elastyczność

Inne znaki mogą być stosowane zamiast znaków l, r, f, i u, ale muszą one być wyraźnie udokumentowane.

Tablica wyników

Dzięki @Optimizer za utworzenie następującego fragmentu kodu. Aby użyć, kliknij „Pokaż fragment kodu”, przewiń w dół i kliknij „► Uruchom fragment kodu”.


źródło
3
Jaki może być drugi parametr? To może być "rrfrburb"? Ponadto, kiedy przesuwa się lub odwraca bity, czy robi to dla każdej pojedynczej litery lub ciągu jako całości? Więcej przypadków testowych by to wyjaśniło.
xnor
1
Masz na myśli przesunięcie lub obrót? przesunięcie w lewo w C spowoduje utratę skrajnego lewego bitu, a skrajny prawy bicie zero. W przypadku przesunięcia praw dla niepodpisanego numeru dzieje się odwrotnie. W przypadku numeru ze znakiem nie jestem pewien, czy istnieje uniwersalnie zdefiniowane zachowanie dla tego, co zostanie przesunięte dla liczb ujemnych (czy to 0 czy 1?) Tak czy inaczej, informacje są zawsze tracone podczas przeprowadzania zmiany, co nie jest przypadkiem na obrót.
Level River St
2
FWIW jest już jedno pytanie oparte na tym XKCD .
Peter Taylor
2
@flawr, nie sądzę, by miałoby to jakąkolwiek przewagę nad obecną możliwością wyszukiwania „xkcd”
Peter Taylor
1
@KSFT Myślę, że będę musiał odmówić. Stwórz ciąg, łącząc się z nim.

Odpowiedzi:

1

CJam, 34 32 bajty

1l+256b2b1>l{~"11W:mm%!<>">4%~}/

W instrukcji użyto następujących znaków:

0: left rotation
1: right rotation
2: reverse
3: flip

Dane wejściowe są pobierane ze STDIN ze słowem w pierwszym wierszu i ciągiem instrukcji w drugim wierszu.

Sprawdź to tutaj.

Wyjaśnienie

Uzyskanie ciągu bitowego jest tak naprawdę kwestią interpretacji kodów znaków jako cyfr liczby base-256 (i uzyskania jej reprezentacji base-2). Trudne jest to, że ta ostatnia podstawowa konwersja nie spowoduje uzupełnienia wyniku zerami po lewej stronie. Dlatego dodam wiodącą 1 do początkowego wejścia, a następnie ponownie podzielę tę 1 w reprezentacji binarnej. Na przykład, jeśli dane wejściowe to ab, przekształcam je w tablicę [1 'a 'b], interpretuję to jako base-256 (znaki są automatycznie konwertowane na kody znaków), czyli 90466i na base-2, czyli [1 0 1 1 0 0 0 0 1 0 1 1 0 0 0 1 0]. Teraz, jeśli po prostu usunę tę wiodącą 1, mam strumień bitów, którego szukam.

Tak właśnie działa ta część kodu:

1l+256b2b1>

Teraz czytam listę instrukcji i wykonuję blok dla każdego znaku w ciągu instrukcji:

l{...}/

Pierwszą rzeczą do zrobienia jest, aby ocenić charakter i rzeczywiste liczby całkowite 0, 1, 2lub 3. Teraz prawdziwa magia golfa ... w zależności od instrukcji chcę uruchomić krótki fragment kodu, który implementuje operację:

Integer:  Code  Operation
0         1m<   "Left rotation";
1         1m>   "Right rotation";
2         W%    "Reverse";
3         :!    "Flip each bit";

Mógłbym przechowywać je w tablicy bloków i wybrać odpowiedni blok do uruchomienia, ale kodowanie ich w ciągu jest w rzeczywistości krótsze:

"11W:mm%!<>">4%~

Najpierw używam liczby całkowitej powiązanej z instrukcją, aby odciąć początek łańcucha. Tak więc w przypadku obrotu w lewo ciąg znaków pozostaje niezmieniony, w przypadku obrotu w prawo pierwszy znak jest odrzucany i tak dalej. Następnie wybieram co czwarty znak z ciągu, zaczynając od pierwszego, z 4%. Zwróć uwagę, jak cztery fragmenty kodu są rozmieszczone w całym ciągu. Wreszcie po prostu oceniam ciąg jako kod ~.

Łańcuch bitów jest drukowany automatycznie na końcu programu.

Martin Ender
źródło
Dlaczego 1m<zamiast (+? Pracujesz nad tablicą, a nie liczbą, prawda?
Peter Taylor,
@Peter, prawda, dzięki. Naprawię to później.
Martin Ender,
2

CJam, 34 bajty

Inne podejście w CJam.

1l+256b2b1>l_S/,1&@f=_,,@f{W%~}\f=

Tekst wejściowy znajduje się w pierwszym wierszu, a instrukcje w drugim wierszu.

Instrukcje:

)        Rotate left.
(        Rotate right.
 (space) Flip.
~        Reverse.
jimmy23013
źródło
1
To całkiem sprytne. Szkoda, która f~nie została wdrożona, prawda? ;)
Martin Ender
2

Pyth 33

jku@[+eGPG+tGhG_Gms!dG)sHwsmjCk2z

Wykorzystuje:

0    : rotate right
1    : rotate left
2    : reverse order
3    : flip values

Pyth github

Wypróbuj online tutaj.

Jest to program, który przyjmuje ciąg znaków jako pierwszy argument, a ciąg poleceń jako drugi argument. W wersji online powinieneś podać ciągi znaków oddzielone znakiem nowej linii, na przykład:

AbC
0321

Wyjaśnienie:

                                    : z=input() (implicit)
jk                                  : join("", ...)
  u@[                 )sHw          : reduce(select from [...] the value at int(H), input(), ...)
     +eGPG                          : [ G[-1] + G[:1],
          +tGhG                     : G[1:] + G[1],
               _G                   : G[::-1],
                 ms!dG              : map(lambda d: int(not(d)), G) ]
                          smjCk2z   : first arg = sum(map(lambda k:convert_to_base(ord(k),2),z)

Coś, do czego nie mogłem się wcisnąć: Pyth reduceautomatycznie używa Gpoprzedniej wartości i Hnastępnej wartości.

FryAmTheEggman
źródło
Tracisz dotyk? Tylko 1 bajt krótszy niż CJam?
Optymalizator
@Optimizer Właściwie mogę to pokonać, stosując te same instrukcje. Ale nie sądziłem, że to będzie ważne, ponieważ wyzwanie mówi „ Zamiast tego można użyć innych literlrfu , ale muszą być one wyraźnie udokumentowane”. (moje podkreślenie)
Martin Ender
1

Scala - 192

def f(i:String,l:String)=(i.flatMap(_.toBinaryString).map(_.toInt-48)/:l){
case(b,'l')⇒b.tail:+b.head
case(b,'r')⇒b.last+:b.init
case(b,'f')⇒b.map(1-_)
case(b,'u')⇒b.reverse}.mkString
Gilad Hoch
źródło
1

Matlab (166 bajtów)

Używa odpowiednio liter abcdzamiast lrfu.

function D=f(B,C)
D=dec2bin(B,8)';
D=D(:);
g=@circshift;
for c=C
switch c-97
case 0
D=g(D,-1);
case 1
D=g(D,1);
case 2
D=char(97-D);
case 3
D=flipud(D);
end
end
D=D';

Niektóre sztuczki użyte tutaj, aby zaoszczędzić miejsce:

  • Korzystanie abcdlitery pozwala mi odjąć 97jeden raz, a następnie litery stać 0, 1, 2, 3. Oszczędza to miejsce w klauzulach switch- case.
  • Zdefiniowanie circshiftjako jednoliterowej funkcji anonimowej również oszczędza miejsce, ponieważ jest używane dwukrotnie.
  • Ponieważ Dskłada się z '0'i '1'znaków (kody ASCII 48i 49), instrukcja D=char(97-D)odpowiada inwersji między '0'i '1'wartościami. Pamiętaj, że 97nie ma to nic wspólnego z tym, o którym mowa powyżej.
  • 'Zamiast transpozycji stosowana jest transpozycja złożonego sprzężonego .'.
Luis Mendo
źródło
0

Python 2 - 179

b="".join([bin(ord(i))[2:]for i in input()])
for i in input():b=b[-1]+b[:-1]if i=="r"else b[1:]+b[0]if i=="l"else[str("10".find(j))for j in b]if i=="f"else b[::-1]
print"".join(b)
KSFT
źródło
0

C #, 418 bajtów

using System;using System.Collections.Generic;using System.Linq;class P{string F(string a,string o){var f=new Dictionary<char,Func<string,IEnumerable<char>>>{{'l',s=>s.Substring(1)+s[0]},{'r',s=>s[s.Length-1]+s.Substring(0,s.Length-1)},{'u',s=>s.Reverse()},{'f',s=>s.Select(c=>(char)(97-c))}};return o.Aggregate(string.Join("",a.Select(c=>Convert.ToString(c,2).PadLeft(8,'0'))),(r,c)=>new string(f[c](r).ToArray()));}}

Sformatowany:

using System;
using System.Collections.Generic;
using System.Linq;

class P
{
    string F(string a, string o)
    {
        // define string operations
        var f = new Dictionary<char, Func<string, IEnumerable<char>>>
        {
            {'l', s => s.Substring(1) + s[0]},
            {'r', s => s[s.Length - 1] + s.Substring(0, s.Length - 1)},
            {'u', s => s.Reverse()},
            {'f', s => s.Select(c => (char) (97 - c))}
        };
        // for each operation invoke f[?]; start from converted a
        return o.Aggregate(
            // convert each char to binary string, pad left to 8 bytes and join them
            string.Join("", a.Select(c => Convert.ToString(c, 2).PadLeft(8, '0'))),
            // invoke f[c] on result of prev operation
            (r, c) => new string(f[c](r).ToArray())
        );
    }
}
Krzysztof
źródło
0

J, 164

([: >@:}. (([: }. >&{.) ; >@:{.@:>@:{. 128!:2 >@:}.)^:({.@:$@:>@:{.))@:(>@:((<;._1 ' 1&|."1 _1&|."1 -. |."1') {~ 'lrfu' i. 0&({::)@:]) ; ;@:([: (8$2)&#: a. i. 1&({::)))

Sformatowany:

nextop=:([: }. >&{.)
exec=: (>@:{.@:>@:{.) apply"1 >@:}.
times=: ({.@:$@:>@:{.)
gapply=: [: >@:}. (nextop ; exec)^:(times) f.

tobin=: ;@:([: (8#2)&#:(a.i.1&{::))
g=:'1&|.';'_1&|.';'-.';'|.'
tog =:  g {~ ('lrfu' i. 0&{::@:])
golf=: gapply @: (>@:tog;tobin)  f.

Przykład

golf ('rfu';'b')
0 1 1 1 0 0 1 1


golf ('lruuff';'b')
0 1 1 0 0 0 1 0

(8#2)#: 98
0 1 1 0 0 0 1 0

golf ('lruuff';'AB')
0 1 0 0 0 0 0 1 0 1 0 0 0 0 1 0

tobin '';'AB'
0 1 0 0 0 0 0 1 0 1 0 0 0 0 1 0
joebo
źródło
0

JavaScript (E6), 163 167

W pełni wykorzystująca elastyczność wprowadzania nazwana funkcja z 2 parametrami tablicy.

  • Pierwszy parametr, tablica bajtów odpowiadająca 7-bitowym kodom znaków
  • Drugi parametr, tablica bajtów odpowiadająca znakom ascii „F”, „L”, „R”, „U” -> 70, 76, 82, 85

Funkcja zwraca ciąg znaków złożony z „1” i „0”

F=(a,s,r='')=>
  a.map(c=>r+=(128|c).toString(2).slice(-7))-
  s.map(c=>a=c<71?a.map(c=>1-c):c<77?a.concat(a.shift):c<83?[a.pop(),...a]:a.reverse(),a=[...r])
  ||a.join('')

Przykład f("b", "rfu") przetłumacz na F([98],[82,70,85]), wynikiem jest0111001

Uwaga: używanie ciągów znaków jest o wiele dłuższe w javascript! Liczba bajtów 186

F=(a,s,r='')=>
  [for(c of a)r+=(128|c.charCodeAt()).toString(2).slice(-7)]-
  [for(c of(a=[...r],s))a=c<'G'?a.map(c=>1-c):c<'M'?a.concat(a.shift):c<'S'?[a.pop(),...a]:a.reverse()]
  ||a.join('')

Przykład F("b", "RFU") , wynik jest 0111001ponownie

edc65
źródło
0

Ruby, 151

f=->i,s{s.chars.inject(i.unpack("B*")[0]){|a,c|
a.reverse! if c==?u
a.tr!"01","10" if c==?f
a<<a.slice!(1..-1) if c==?l
a<<a.slice!(0..-2) if c==?r
a}}

Dość bezpośredni. Pętle przechodzą przez postacie si wykonują akcję dla dowolnej z nich.

Britishtea
źródło
0

Python 2, 142

j="".join
f=lambda S,I:reduce(lambda s,i:[s[1:]+s[0],s[-1]+s[:-1],s[::-1],j([`1^int(c)`for c in s])][int(i)],I,j([bin(ord(c))[2:]for c in S]))

Podobna do mojej odpowiedzi pyta w podejściu: buduję listę wszystkich ciągów i indeksuję do niej na podstawie wartości ciągu instrukcji, nad którym iteruję, używając redukcji.

Wykorzystuje:

0  ->  Rotate left
1  ->  Rotate right
2  ->  Reverse order
3  ->  Invert bits
FryAmTheEggman
źródło