OOP: programmazione orientata sovrapposta


32

Uno dei paradigmi di programmazione meno conosciuti che sembra piuttosto appropriato per il golf di codice è la programmazione orientata a sovrapposizione (OOP) *. Quando si scrive un codice parzialmente identico, è possibile salvare molti byte semplicemente sovrapponendo le parti identiche e ricordando in qualche modo dove iniziano le due righe di codice originali. Il tuo compito è scrivere due programmi o funzioni sovrapposticompress e decompresscon le seguenti specifiche:

* Non utilizzare nel codice di produzione, probabilmente.

compress

compressprende due stringhe in qualsiasi formato conveniente e le sovrappone il più possibile. sViene restituita una stringa di lunghezza minima in modo tale che entrambe le stringhe di input siano sottostringhe di s. Inoltre, viene restituito un output che identifica gli indici di inizio e fine di entrambe le stringhe.

Esempi: (L'esatto formato IO dipende da te)

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

decompresscalcola la funzione inversa di compress, a cui viene data una stringa e due indici di inizio e fine (nel formato in cui sono restituiti dal tuo compress), restituisce le due stringhe originali. Devi solo gestire input validi. Il seguente uguaglianza deve valere per tutte le stringhe s1, s2:

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

Esempi: (inversioni di compressesempi)

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"

punteggio

Il tuo punteggio è la dimensione della stringa restituita chiamando compress("<code of compress>", "<code of decompress>"). Dato che si tratta di un punteggio più basso è migliore.

Esempio:

Supponiamo che il codice per la tua funzione compresssia c=abcde il codice per decompresssia d=efghi. Quindi i compress("c=abcd", "d=efghi")rendimenti "c=abcd=efghi"(e gli indici, ma quelli non influiscono sul punteggio), quindi il punteggio è length "c=abcd=efghi" = 12.

Regole aggiuntive

  • Nello spirito di questa sfida, il tuo compresse decompress deve sovrapporsi in almeno un personaggio. Puoi ottenere ciò in modo banale aggiungendo un commento, ma nota che facendo ciò aumenterai il tuo punteggio e potrebbero esserci soluzioni più brevi usando un codice intrinsecamente sovrapposto.
  • compresse decompressdovrebbe essere in grado di gestire stringhe contenenti caratteri ASCII stampabili e tutti i caratteri che hai usato per definire compresse decompress.
  • Gli indici possono essere zero o uno-indicizzati.
  • I tuoi programmi o funzioni non devono essere effettivamente nominati compresse decompress.

È possibile utilizzare diversi argomenti della riga di comando per eseguire la compressione e decompressione del codice?
MildlyMilquetoast

Sicuro. Devi fornire due programmi e la politica del sito consente gli argomenti della riga di comando fintanto che vengono conteggiati, quindi puoi fornire diversi argomenti della riga di comando per ciascuno dei tuoi programmi.
Laikoni,

Risposte:


25

GNU Prolog, 105 punti

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

(Ciò richiede GNU Prolog perché prefixe suffixnon sono portatili.)

Prolog ha un vantaggio interessante e importante per questa sfida; puoi scrivere una funzione per gestire più schemi di chiamata (cioè non solo puoi dare alla funzione un input per ottenere un output corrispondente, puoi dare alla funzione un output per ottenere l'input corrispondente). Pertanto, possiamo definire una funzione in grado di gestire sia la compressione che la decompressione, portando a un invio di 105 byte che definisce una funzione oche funziona in entrambi i modi. (Per inciso, l'ho scritto principalmente come decompressore - in quanto è più semplice - e ho ottenuto il compressore "gratis".) In generale, potremmo aspettarci un programma molto breve in Prolog per questo compito, se non per il fatto che è così male alla gestione delle stringhe (sia in termini di primitive mancanti, sia in termini di primitivi in ​​questione che hanno nomi terribilmente lunghi).

Il primo argomento oè una tupla di stringhe, ad es "abcd"-"deab". Il secondo argomento ha una forma simile "deabcd"-4/6-4/4; questa è una tupla nidificata abbastanza standard e significa che la stringa è "deabcd", la prima stringa ha lunghezza 4 e termina al sesto carattere, la seconda stringa ha lunghezza 4 e termina al quarto carattere. (Nota che una stringa in GNU Prolog è solo un elenco di codici carattere, il che rende fastidioso il debug perché l'implementazione preferisce quest'ultima interpretazione di default.) Se daioun argomento, produrrà l'altro per te (funzionando così come un compressore se dai il primo argomento e un decompressore se dai il secondo). Se gli dai entrambi gli argomenti, verificherà che la rappresentazione compressa corrisponda alle stringhe fornite. Se gli dai zero argomenti, genererà un output in questo modo:

| ?- 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 descrizione sopra del formato I / O è praticamente solo una descrizione del programma; non c'è molto nel programma. L'unica sottigliezza riguarda i suggerimenti per gli ordini di valutazione; dobbiamo assicurarci che il programma non utilizzi solo una strategia di ricerca che è garantita per terminare, ma produce anche la stringa di output più breve possibile.

Quando comprimiamo, iniziamo con length(C,_)(" Chas a length"), che è un trucco che ho usato in molte risposte di Prolog e Brachylog; se questa è la prima cosa che Prolog vede, lo farà dare la priorità riducendo la lunghezza di Cqualsiasi altra cosa. Questo assicura che abbiamo una lunghezza minima C. L'ordinamento dei vincoli sè scelto con cura in modo che la ricerca impiegherà un tempo finito per ogni possibile lunghezza del candidato di C; Aè limitato da C(non lo sappiamo C, ma conosciamo il valore target che abbiamo per la sua lunghezza), Mda A, Uda Ae Lda U, quindi nessuna delle ricerche può richiedere un tempo illimitato.

Durante la decompressione, ci viene fornito Cdirettamente dall'utente. Ciò garantisce nuovamente che il programma verrà eseguito a tempo finito, a causa della stessa sequenza di vincoli. (Le persone che sono a conoscenza dell'ordine di valutazione di Prolog noteranno che la definizione di sè molto inefficiente durante la decompressione; il posizionamento length(A,M)e il length(U,L)primo sarebbero più veloci, ma spostarsi length(A,M)all'inizio potrebbe causare un ciclo infinito durante la compressione perché né AMè legato da nulla al momento .)


13

Brachylog , 50 46 byte

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

Provalo online!

Decomprimere:

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

Provalo online!

5 byte salvati grazie a @ ais523

Spiegazione

Il lato positivo dei linguaggi dichiarativi è che possiamo riutilizzare lo stesso codice sia per la compressione che per la decompressione. Pertanto, il codice per compress è esattamente lo stesso di decompress , con un ulteriore ~all'inizio.

Questo ~dice a Brachylog di invertire l'ordine degli argomenti (ovvero, utilizzare Input come output e Output come input). Poiché compress non ha ~, in realtà esegue il predicato nell'ordine standard. Poiché decompress ne ha solo uno, lo esegue con Input come output e Output come input.

In questo modo, possiamo usare lo stesso codice (modulo che extra ~) sia per comprimere che per decomprimere: la compressione sta fornendo le due stringhe come input e una variabile come output, e la decompressione sta fornendo gli indici e la stringa compressa come output e una variabile come Input .

Ovviamente questo significa anche che dobbiamo essere un po 'espliciti sul nostro codice di compressione, in modo che l'interprete sia in grado di eseguirlo "all'indietro". Ecco perché il compressore stesso è un po 'lungo.

Ecco una ripartizione del codice per Compress (e quindi anche di decompressioni):

{……………………………………………………………………}   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]

4

Gelatina , 58 50 byte

-1 byte grazie a ais523 (utilizzare per una stringa a due byte)

Questo potrebbe benissimo essere giocabile a golf ...

La compressione accetta due argomenti stringa e restituisce un elenco:
[[[startA, lengthA], [startB, lengthB]], compressedString]

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

La decompressione accetta un argomento (un tale elenco) e restituisce due * stringhe:

,
⁾ṫḣżFv
Ḣç€Ṫ

Codice sovrapposto:

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

One-indicizzato.

* questo potrebbe non essere ovvio a causa della formattazione di stampa implicita di Jelly, quindi il codice su TryItOnline collegato sopra ha un byte extra ( Ya alla fine) per inserire un avanzamento di riga tra i due nell'output stampato.

Ho iniziato con un singolo programma, che ha utilizzato la profondità del primo (o unico) argomento per decidere tra compressione e decompressione, ma avere un collegamento inutilizzato nel codice di decompressione (la prima riga) e un singolo byte sovrapposto è più breve di sette byte .

Come?

ç;ç@ÑẠ$Ð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.

“ṫḣ”può essere giocato a golf di 1 byte usando la sintassi di Jelly per stringhe di 2 caratteri.

Questa è una domanda completamente estranea alla risposta di per sé, ma scrivi a mano la spiegazione del codice o esiste uno strumento che lo genera dal codice?
Tfrascaroli,

@tfrascaroli Lo scrivo a mano
Jonathan Allan il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.