POO: Programmation Orientée Chevauchement

32

L'un des paradigmes de programmation les moins connus qui semble plutôt approprié pour le golf de code est Overlapping Oriented Programming (OOP) *. Lors de l'écriture de code partiellement identique, de nombreux octets peuvent être enregistrés en chevauchant simplement les parties identiques et en se souvenant d'une manière où les deux lignes de code d'origine commencent. Votre tâche consiste à écrire deux programmes ou fonctions qui se chevauchentcompress et decompressavec les spécifications suivantes:

* Ne pas utiliser dans le code de production, probablement.

compress

compressprend deux chaînes dans n'importe quel format pratique et les chevauche autant que possible. C'est-à-dire qu'une chaîne sde longueur minimale est renvoyée de telle sorte que les deux chaînes d'entrée sont des sous-chaînes de s. De plus, une sortie identifiant les indices de début et de fin des deux chaînes est renvoyée.

Exemples: (Le format IO exact dépend de vous)

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

decompresscalcule la fonction inverse de compress, qui est donnée une chaîne et deux indices de début et de fin (dans le format dans lequel ils sont retournés par votre compress), renvoyer les deux chaînes d'origine. Vous n'avez besoin que de gérer des entrées valides. L'égalité suivante devrait tenir toutes les chaînes s1, s2:

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

Exemples: (inverses d' compressexemples)

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"

Notation

Votre score est la taille de la chaîne retournée en appelant compress("<code of compress>", "<code of decompress>"). Comme il s'agit de un score inférieur est meilleur.

Exemple:

Supposons que le code de votre fonction compressest c=abcdet que le code de decompressest d=efghi. Ensuite, les compress("c=abcd", "d=efghi")rendements "c=abcd=efghi"(et les indices, mais ceux-ci n'affectent pas le score), le score est donc length "c=abcd=efghi" = 12.

Règles supplémentaires

  • Dans l'esprit de ce défi, votre compresset decompress doit se chevaucher dans au moins un caractère. Vous pouvez y parvenir de manière triviale en ajoutant un commentaire, mais notez que cela augmentera votre score et il pourrait y avoir des solutions plus courtes utilisant du code se chevauchant intrinsèquement.
  • compresset decompressdevrait être capable de gérer les chaînes contenant tous les caractères ASCII imprimables ainsi que tous les caractères que vous avez utilisés pour définir compresset decompress.
  • Les indices peuvent être indexés à zéro ou à un.
  • Vos programmes ou fonctions n'ont pas besoin d'être nommés compresset decompress.
Laikoni
la source
Pouvez-vous utiliser différents arguments de ligne de commande pour exécuter le code de compression et de décompression?
MildlyMilquetoast
Sûr. Vous devez donner deux programmes et la stratégie de site autorise les arguments de ligne de commande tant qu'ils sont comptés, vous pouvez donc donner des arguments de ligne de commande différents pour chacun de vos programmes.
Laikoni

Réponses:

25

GNU Prolog, 105 points

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).

(Cela nécessite GNU Prolog car prefixet suffixn'est pas portable.)

Prolog a un avantage intéressant et majeur pour ce défi; vous pouvez écrire une fonction pour gérer plusieurs modèles d'appel (c.-à-d. non seulement vous pouvez donner à la fonction une entrée pour obtenir une sortie correspondante, vous pouvez donner à la fonction une sortie pour obtenir l'entrée correspondante). En tant que tel, nous pouvons définir une fonction qui peut gérer à la fois la compression et la décompression, conduisant à une soumission de 105 octets qui définit une fonctiono qui fonctionne dans les deux sens. (Soit dit en passant, je l'ai principalement écrit en tant que décompresseur - car c'est plus simple - et j'ai obtenu le compresseur "gratuitement".) En général, nous pourrions nous attendre à un programme très court dans Prolog pour cette tâche, sinon pour le fait qu'il est si mauvais à la gestion des chaînes (à la fois en termes de primitives manquantes et en termes de primitives en question ayant des noms terriblement longs).

Le premier argument de oest un tuple de chaînes, par exemple "abcd"-"deab". Le deuxième argument a une forme comme "deabcd"-4/6-4/4; il s'agit d'un tuple imbriqué assez standard et signifie que la chaîne est "deabcd", la première chaîne a une longueur 4 et se termine au sixième caractère, la deuxième chaîne a une longueur 4 et se termine au quatrième caractère. (Notez qu'une chaîne dans GNU Prolog n'est qu'une liste de codes de caractères, ce qui rend le débogage ennuyeux car l'implémentation préfère la dernière interprétation par défaut.) Si vous donnezo un argument, il produira l'autre pour vous (fonctionnant ainsi comme un compresseur si vous donnez le premier argument, et un décompresseur si vous donnez le second). Si vous lui donnez les deux arguments, il vérifiera que la représentation compressée correspond aux chaînes données. Si vous ne lui donnez aucun argument, il générera une sortie comme celle-ci:

| ?- 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 ? ;

La description ci-dessus du format d'E / S est à peu près entièrement une description du programme également; il n'y a pas grand-chose dans le programme. La seule subtilité est liée aux conseils d'ordre d'évaluation; nous devons nous assurer que le programme n'utilise pas seulement une stratégie de recherche dont la fin est garantie, mais produit également la chaîne de sortie la plus courte possible.

Lors de la compression, nous commençons par length(C,_)(" Ca une longueur"), ce qui est une astuce que j'ai utilisée dans de nombreuses réponses Prolog et Brachylog; si c'est la première chose que Prolog voit, cela lui fera prioriser la réduction de la longueur par Crapport à toute autre chose. Cela garantit que nous avons une longueur minimale C. L'ordre des contraintes dans sest soigneusement choisi pour que la recherche prenne un temps fini pour chaque longueur possible de candidat C; Aest contraint par C(nous ne savons pas C, mais nous connaissons la valeur cible que nous avons pour sa longueur), Mpar A, Upar Aet Lpar U, donc aucune des recherches ne peut prendre un temps illimité.

Lors de la décompression, nous sommes donnés Cdirectement par l'utilisateur. Cela garantit à nouveau que le programme fonctionnera en temps fini, en raison de la même séquence de contraintes. (Les personnes qui connaissent l'ordre d'évaluation de Prolog noteront que la définition de sest très inefficace lors de la décompression; le placement length(A,M)et le length(U,L)premier seraient plus rapides, mais le déplacement length(A,M)vers le début pourrait provoquer une boucle infinie lors de la compression car ni l'un Ani l'autre Mn'est lié par quoi que ce soit à l'époque .)


la source
13

Brachylog , 50 46 octets

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

Essayez-le en ligne!

Décompresser:

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

Essayez-le en ligne!

5 octets enregistrés grâce à @ ais523

Explication

Le bon côté des langages déclaratifs est que nous pouvons réutiliser le même code pour la compression et la décompression. En tant que tel, le code pour compresser est exactement le même que pour décompresser , avec un supplémentaire ~au début.

Cela ~indique à Brachylog d'inverser l'ordre des arguments (c'est-à-dire d'utiliser l'entrée comme sortie et la sortie comme entrée). Puisque compress n'a pas ~, il exécute en fait le prédicat dans l'ordre standard. Comme la décompression n'en a qu'une seule, elle l'exécute avec l'entrée en sortie et la sortie en entrée.

De cette façon, nous pouvons utiliser le même code (modulo that extra ~) pour compresser et décompresser: la compression fournit les deux chaînes en entrée et une variable en sortie, et la décompression fournit les index et la chaîne compressée en sortie et une variable en entrée .

Évidemment, cela signifie également que nous devons être un peu explicites sur notre code de compression, afin que l'interpréteur soit capable de l'exécuter "à l'envers". C'est pourquoi le compresseur lui-même est un peu long.

Voici une ventilation du code pour Compress (et donc aussi de décompresser):

{……………………………………………………………………}   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]
Fataliser
la source
4

Gelée , 58 50 octets

-1 octet grâce à ais523 (à utiliser pour une chaîne de deux octets)

Cela peut être assez golfable ...

La compression prend deux arguments de chaîne et renvoie une liste:
[[[startA, lengthA], [startB, lengthB]], compressedString]

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

La décompression prend un argument (une telle liste) et renvoie deux chaînes *:

,
⁾ṫḣżFv
Ḣç€Ṫ

Code superposé:

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

Un index.

* cela peut ne pas être évident en raison de la mise en forme d'impression implicite de Jelly, donc le code de TryItOnline lié à ci-dessus a un octet supplémentaire (un Yà la fin) pour insérer un saut de ligne entre les deux dans la sortie imprimée.

J'ai commencé avec un seul programme, qui utilisait la profondeur du premier (ou unique) argument pour décider entre la compression et la décompression, mais ayant un lien inutilisé dans le code de décompression (la première ligne) et un seul octet se chevauchant est plus court de sept octets .

Comment?

ç;ç@ÑẠ$Ð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
la source
“ṫḣ”peut être joué sur 1 octet en utilisant la syntaxe de Jelly pour les chaînes de 2 caractères.
Il s'agit d'une question totalement indépendante de la réponse en soi, mais écrivez-vous l'explication du code à la main ou existe-t-il un outil qui le génère à partir du code?
tfrascaroli
@tfrascaroli Je l'écris à la main
Jonathan Allan