OOP: Programação Orientada Sobreposta

32

Um dos paradigmas de programação menos conhecidos que parece bastante adequado para o golfe com código é a Programação Orientada por Sobreposição (OOP) *. Ao escrever código parcialmente idêntico, muitos bytes podem ser salvos simplesmente sobrepondo as partes idênticas e lembrando de alguma maneira que as duas linhas de código originais começam. Sua tarefa é escrever dois programas ou funções sobrepostoscompress e decompresscom a seguinte especificação:

* Não use no código de produção, provavelmente.

compress

compresspega duas strings em qualquer formato conveniente e as sobrepõe o máximo possível. Essa é uma string scom comprimento mínimo retornada de forma que ambas as strings de entrada sejam substrings de s. Além disso, é retornada alguma saída que identifica os índices inicial e final de ambas as seqüências.

Exemplos: (O formato exato de IO depende de você)

compress("abcd", "deab") -> "deabcd" ((2,5),(0,3))
compress("abcd", "bc")   -> "abcd" ((0,3),(1,2))
compress("abc", "def")   -> "abcdef" ((0,2),(3,5)) or "defabc" ((3,5),(0,2))

decompress

decompresscalcula a função inversa de compress, que recebe uma sequência e dois índices inicial e final (no formato em que são retornados pelo seu compress), retorna as duas sequências originais. Você só precisa manipular entradas válidas. A seguir a igualdade deveria valer para todas as cordas s1, s2:

(s1, s2) == decompress (compress (s1, s2))

Exemplos: (inversos de compressexemplos)

decompress "deabcd" ((2,5),(0,3)) -> "abcd" "deab" 
decompress "abcd" ((0,3),(1,2))   -> "abcd" "bc"

decompress "abcdef" ((0,2),(3,5)) -> "abc" "def"   
 or (whichever version your "compress" generates)
decompress "defabc" ((3,5),(0,2)) -> "abc" "def"

Pontuação

Sua pontuação é o tamanho da string retornada chamando compress("<code of compress>", "<code of decompress>"). Como este é um uma pontuação menor é melhor.

Exemplo:

Suponha que o código para sua função compressseja c=abcde o código para decompressseja d=efghi. Então compress("c=abcd", "d=efghi")produz "c=abcd=efghi"(e os índices, mas esses não afetam a pontuação), então a pontuação é length "c=abcd=efghi" = 12.

Regras adicionais

  • No espírito deste desafio, você devecompress e decompress deve se sobrepor em pelo menos um personagem. Você pode conseguir isso trivialmente adicionando um comentário, mas observe que isso aumentará sua pontuação e poderá haver soluções mais curtas usando código inerentemente sobreposto.
  • compresse decompressdeve ser capaz de lidar com cadeias de caracteres que contenham caracteres ASCII imprimíveis, além de todos os caracteres usados ​​para definir compresse decompress.
  • Os índices podem ser zero ou um indexados.
  • Seus programas ou funções não precisam ser nomeados compresse decompress.
Laikoni
fonte
Você pode usar argumentos de linha de comando diferentes para executar a compactação e descompactação do código?
MildlyMilquetoast
Certo. Você precisa fornecer dois programas e a política do site permite argumentos de linha de comando, contados, para que você possa fornecer argumentos de linha de comando diferentes para cada um dos seus programas.
Laikoni

Respostas:

25

GNU Prolog, 105 pontos

s(U,L/M,C):-prefix(A,C),length(A,M),suffix(U,A),length(U,L).
o(A-B,C-X-Y):-length(C,_),s(A,X,C),s(B,Y,C).

(Isso requer o GNU Prolog porque prefixe suffixnão é portátil.)

O Prolog tem uma grande vantagem interessante para esse desafio; você pode escrever uma função para lidar com vários padrões de chamada (ou seja, não apenas pode fornecer uma função para obter uma saída correspondente, mas também pode fornecer uma função para obter uma entrada correspondente). Como tal, podemos definir uma função que pode lidar com compactação e descompactação, levando a um envio de 105 bytes que define uma função oque funciona nos dois sentidos. (Aliás, eu principalmente escrevi como um descompressor - como é mais simples - e adquiri o compressor "de graça".) Em geral, poderíamos esperar um programa muito curto no Prolog para essa tarefa, se não pelo fato de ser tão ruim. no tratamento de strings (tanto em termos de primitivas ausentes quanto em termos de primitivas em questão com nomes terrivelmente longos).

O primeiro argumento para oé uma tupla de strings, por exemplo "abcd"-"deab". O segundo argumento tem uma forma como "deabcd"-4/6-4/4; essa é uma tupla aninhada bastante padrão e significa que a string é "deabcd", a primeira string tem comprimento 4 e termina no sexto caractere, a segunda string tem comprimento 4 e termina no quarto caractere. (Observe que uma string no GNU Prolog é apenas uma lista de códigos de caracteres, o que torna a depuração irritante porque a implementação prefere a última interpretação por padrão.) Se você forneceroum argumento, ele produzirá o outro para você (trabalhando assim como um compressor se você der o primeiro argumento e um descompressor se você der o segundo). Se você fornecer os dois argumentos, verificará se a representação compactada corresponde às seqüências fornecidas. Se você der zero argumentos, ele gerará uma saída como esta:

| ?- o(X,Y).
X = []-[]
Y = []-0/0-0/0 ? ;

X = []-[]
Y = [_]-0/0-0/0 ? ;

X = []-[A]
Y = [A]-0/0-1/1 ? ;

many lines later

X = [A]-[B,A,C]
Y = [B,A,C]-1/2-3/3 ? ;

A descrição acima do formato de E / S também é basicamente apenas uma descrição do programa; não há muito no programa. A única sutileza está relacionada às dicas de ordem de avaliação; precisamos garantir que o programa não use apenas uma estratégia de pesquisa com garantia de término, mas também produza a menor string de saída possível.

Ao compactar, começamos com length(C,_)(" Ctem um comprimento"), que é um truque que já usei em muitas respostas do Prolog e Brachylog; se essa é a primeira coisa que o Prolog vê, fará com que ele priorize a redução do tamanho de Cqualquer outra coisa. Isso garante que tenhamos um comprimento mínimo C. A ordenação das restrições sé cuidadosamente escolhida para que a pesquisa leve um tempo finito para cada comprimento possível de candidato C; Aé limitado por C(não sabemos C, mas sabemos o valor-alvo que temos para o seu comprimento), Mpor A, Upor Ae Lpor U, para que nenhuma das pesquisas demore um tempo ilimitado.

Ao descompactar, somos dados Cdiretamente pelo usuário. Isso novamente garante que o programa seja executado em tempo finito, devido à mesma sequência de restrições. (As pessoas que estão cientes da ordem de avaliação do Prolog notarão que a definição de sé muito ineficiente ao descomprimir; colocar length(A,M)e length(U,L)primeiro seria mais rápido, mas passar length(A,M)para o início pode causar um loop infinito na compactação, porque nem Anem Mestá vinculado a nada no momento .)


fonte
13

Braquilog , 50 46 bytes

{Ċ∧Lċ₂l∧Lgj:?z{tT∧?h~cṪhlI∧ṪbhTl:I+-₁:I↔}ᵐ:L}

Experimente online!

Descomprimir:

~{Ċ∧Lċ₂l∧Lgj:?z{tT∧?h~cṪhlI∧ṪbhTl:I+-₁:I↔}ᵐ:L}

Experimente online!

Guardado 5 bytes graças a @ ais523

Explicação

O lado bom das linguagens declarativas é que podemos reutilizar o mesmo código para compactar e descompactar. Como tal, o código para compactar é exatamente o mesmo que para descomprimir , com um adicional ~no início.

Isso ~informa ao Brachylog para reverter a ordem dos argumentos (ou seja, use a Entrada como saída e a Saída como entrada). Como o compress não possui ~, ele realmente executa o predicado na ordem padrão. Como a descompactação possui apenas um, ele é executado com a Entrada como saída e a Saída como entrada.

Dessa forma, podemos usar o mesmo código (módulo extra ~) para compactar e descompactar: ​​a compactação está fornecendo as duas cadeias como entrada e uma variável como saída, e a descompactação está fornecendo os índices e a cadeia compactada como saída e uma variável como Entrada .

Obviamente, isso também significa que precisamos ser um pouco explícitos sobre nosso código de compressão, para que o intérprete seja capaz de executá-lo "de trás para frente". É por isso que o próprio compressor é um pouco longo.

Aqui está um detalhamento do código para Compress (e, portanto, também para descompactar):

{……………………………………………………………………}   Call that predicate the normal way (with swapped arguments
                                 for decompress)
   Ċ                           Input has two elements
   ∧Lċ₂l                       L is a string of any length (measuring its length forces it to
                                 take a specific length from 0 to +inf)
   ∧Lgj                        The list [L,L]
       :?z                     The list [[L, First elem of Input],[L,second elem of input]]
          {………………………………}ᵐ:L    Final output is the [M,L] where M is the result of mapping
                                 the predicate below on both elements of the zip
           tT                  The second element of the input is T
           ∧?h~cṪ              Anticoncatenate the first element of the input into [A,B,C]
           hlI                 I = length(A)
           ∧ṪbhTl:I+-₁         J = length(T) + I - 1
           :I↔                 Output = [I,J]
Fatalizar
fonte
4

Geléia , 58 50 bytes

-1 byte graças a ais523 (use para uma string de dois bytes)

Isso pode muito bem ser jogável ...

A compactação usa dois argumentos de sequência e retorna uma lista:
[[[startA, lengthA], [startB, lengthB]], compressedString]

w³;w⁴$
0;J⁸ḣ;€
ç;ç@ÑẠ$ÐfLÐṂṪµ³,⁴L€ż@Ñ,

A descompressão pega um argumento (como essa lista) e retorna duas * strings:

,
⁾ṫḣżFv
Ḣç€Ṫ

Código sobreposto:

w³;w⁴$
0;J⁸ḣ;€
ç;ç@ÑẠ$ÐfLÐṂṪµ³,⁴L€ż@Ñ,
⁾ṫḣżFv
Ḣç€Ṫ

Um indexado.

* isso pode não ser óbvio devido à formatação implícita de impressão da Jelly, portanto, o código no TryItOnline vinculado acima tem um byte extra (a Yno final) para inserir um avanço de linha entre os dois na saída impressa.

Comecei com um único programa, que usava a profundidade do primeiro (ou único) argumento para decidir entre compactação e descompactação, mas ter um link não utilizado no código de descompactação (a primeira linha) e um único byte sobreposto é menor em sete bytes .

Quão?

ç;ç@ÑẠ$ÐfLÐṂṪµ³,⁴L€ż@Ñ, - Compression: stringA, stringB
ç                       - call the last link (2) as a dyad
  ç@                    - call the last link (2) as a dyad with reversed arguments
 ;                      - concatenate (gives all overlapping strings)
       Ðf               - filter keep:
      $                 -     last two links as a monad
    Ñ                   -         call the next link (1) as a monad
     Ạ                  -         All? (no zeros exist in that result)
          ÐṂ            - filter keep with minimal:
         L              -     length
            Ṫ           - tail (for when more than one exists)
             µ          - monadic chain separation (we now have the compressed string)
              ³,⁴       - [stringA, stringB]
                 L€     - length of €ach
                   ż@   - zip with reversed arguments with
                     Ñ  - next link (1) as a monad with the compressed string
                      , - paired with the compressed string

J0;⁸ḣ;€ - Link 2, possible overlaps: stringL, stringR
J       - range(length(stringL)) - [1,2,...,length(stringL)]
 0;     - zero concatenate       - [0,1,2,...,length(stringL)]
   ⁸    - stringL
    ḣ   - head (vectorises)      - [empty string, first char, first two, ..., stringL]
     ;€ - concatenate €ach with stringR

w³;w⁴$ - Link 1, substring indexes: stringX
w³     - first index of first program argument in stringX or 0 if not found
  ;    - concatenated with
     $ - last two links as a monad
   w⁴  -     first index of second program argument in stringX or 0 if not found
Ḣñ€Ṫ - Decompression: [[[startA, lengthA], [startB, lengthB]], compressedString], ?
Ḣ    - head - [[startA, lengthA], [startB, lengthB]]
   Ṫ - tail - compressedString
 ç€  - call the last link (2) as a dyad for €ach of the left list
     -- extra Y atom at TIO joins the resulting list of two strings with a line feed.

⁾ṫḣżFv - Link 2, extract a substring: [start, length], string
⁾ṫḣ    - string "ṫḣ"
   ż   - zip with [start, length] to yield [['ṫ', start],['ḣ', length]]
    F  - flatten, making a list of characters
     v - evaluate as Jelly code with the string as an argument
       - this evaluates as string.tail(start).head(length) yielding the substring

, - Link 1: only here to make an overlap with the compression program.
Jonathan Allan
fonte
“ṫḣ”pode ter um byte de 1 byte usando a sintaxe de Jelly para seqüências de caracteres de 2 caracteres.
Esta é uma pergunta completamente não relacionada à resposta em si, mas você escreve a explicação do código manualmente ou existe uma ferramenta que o gera a partir do código?
Tfrascaroli 26/01
@tfrascaroli Eu escrevi à mão
Jonathan Allan