OOP: Pemrograman Berorientasi Tumpang tindih

32

Salah satu paradigma pemrograman yang kurang dikenal yang tampaknya cukup pas untuk kode golf adalah Overlapping Oriented Programming (OOP) *. Saat menulis kode yang sebagian identik, banyak byte yang dapat disimpan dengan hanya menumpangtindih bagian-bagian yang identik dan mengingat dengan cara di mana dua baris kode asli dimulai. Tugas Anda adalah menulis dua program atau fungsi yang tumpang tindihcompress dan decompressdengan spesifikasi berikut:

* Jangan gunakan dalam kode produksi, mungkin.

compress

compressmengambil dua string dalam format apa pun yang nyaman dan tumpang tindih sebanyak mungkin. Itu adalah string sdengan panjang minimal dikembalikan sehingga kedua string input adalah substring dari s. Selain itu, beberapa output yang mengidentifikasi indeks awal dan akhir dari kedua string dikembalikan.

Contoh: (Format IO yang tepat terserah Anda)

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

decompressmenghitung fungsi kebalikan dari compress, yang diberi string dan dua indeks awal dan akhir (dalam format di mana mereka dikembalikan oleh Anda compress), mengembalikan dua string asli. Anda hanya perlu menangani input yang valid. Kesetaraan berikut harus berlaku untuk semua string s1, s2:

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

Contoh: (terbalik compresscontoh)

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"

Mencetak gol

Skor Anda adalah ukuran string yang dikembalikan dengan menelepon compress("<code of compress>", "<code of decompress>"). Karena ini adalah skor yang lebih rendah lebih baik.

Contoh:

Asumsikan kode untuk fungsi Anda compressadalah c=abcddan kode untuk decompressadalah d=efghi. Kemudian compress("c=abcd", "d=efghi")menghasilkan "c=abcd=efghi"(dan indeks, tetapi itu tidak mempengaruhi penilaian) sehingga nilainya length "c=abcd=efghi" = 12.

Aturan tambahan

  • Dalam semangat tantangan ini, Anda compressdan decompress harus tumpang tindih dalam setidaknya satu karakter. Anda mungkin mencapai ini sepele dengan menambahkan komentar, tetapi perhatikan bahwa hal itu akan meningkatkan skor Anda dan mungkin ada solusi yang lebih pendek menggunakan kode yang tumpang tindih secara inheren.
  • compressdan decompressharus dapat menangani string yang berisi karakter ASCII yang dapat dicetak serta semua karakter yang Anda gunakan untuk mendefinisikan compressdan decompress.
  • Indeks bisa nol atau satu diindeks.
  • Program atau fungsi Anda tidak harus benar-benar diberi nama compressdan decompress.
Laikoni
sumber
Bisakah Anda menggunakan argumen baris perintah yang berbeda untuk menjalankan kode kompres dan dekompresi?
MildlyMilquetoast
Yakin. Anda harus memberikan dua program dan kebijakan situs memungkinkan argumen baris perintah selama mereka dihitung, sehingga Anda dapat memberikan argumen baris perintah yang berbeda untuk setiap program Anda.
Laikoni

Jawaban:

25

GNU Prolog, 105 poin

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

(Ini memerlukan GNU Prolog karena prefixdan suffixtidak portabel.)

Prolog memiliki satu keuntungan utama yang menarik untuk tantangan ini; Anda dapat menulis fungsi untuk menangani beberapa pola panggilan (yaitu Anda tidak hanya dapat memberikan fungsi input untuk mendapatkan output yang sesuai, Anda dapat memberikan fungsi output untuk mendapatkan input yang sesuai). Dengan demikian, kita dapat mendefinisikan fungsi yang dapat menangani kompresi dan dekompresi, yang mengarah ke pengiriman 105 byte yang mendefinisikan fungsi oyang bekerja dengan dua arah. (Kebetulan, saya sebagian besar menulisnya sebagai dekompresor - karena lebih sederhana - dan mendapat kompresor "gratis".) Secara umum, kita dapat mengharapkan program yang sangat singkat di Prolog untuk tugas ini, jika bukan karena fakta bahwa itu sangat buruk pada penanganan string (baik dalam hal primitif yang hilang, dan dalam hal primitif yang bersangkutan memiliki nama yang sangat panjang).

Argumen pertama oadalah tupel string, misalnya "abcd"-"deab". Argumen kedua memiliki bentuk seperti "deabcd"-4/6-4/4; ini adalah tusuk bersarang yang cukup standar, dan berarti bahwa string tersebut "deabcd", string pertama memiliki panjang 4 dan berakhir pada karakter keenam, string kedua memiliki panjang 4 dan berakhir pada karakter keempat. (Perhatikan bahwa string dalam GNU Prolog hanyalah daftar kode karakter, yang membuat debugging mengganggu karena implementasi lebih memilih interpretasi yang terakhir secara default.) Jika Anda memberikanosatu argumen, itu akan menampilkan yang lain untuk Anda (dengan demikian berfungsi sebagai kompresor jika Anda memberikan argumen pertama, dan dekompresor jika Anda memberikan argumen kedua). Jika Anda memberikan kedua argumen, itu akan memverifikasi bahwa representasi terkompresi cocok dengan string yang diberikan. Jika Anda memberikan argumen nol, itu akan menghasilkan output seperti ini:

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

Deskripsi format I / O di atas hampir seluruhnya hanya deskripsi program, juga; tidak ada banyak dalam program sama sekali. Satu-satunya kehalusan adalah berkaitan dengan petunjuk urutan evaluasi; kita perlu memastikan bahwa program tidak hanya menggunakan strategi pencarian yang dijamin akan berakhir, tetapi juga menghasilkan string keluaran sesingkat mungkin.

Saat mengompresi, kita mulai dengan length(C,_)(" Cmemiliki panjang"), yang merupakan trik yang saya gunakan dalam banyak jawaban Prolog dan Brachylog; jika ini adalah hal pertama yang dilihat Prolog, itu akan membuatnya memprioritaskan pengurangan panjang Cdaripada yang lainnya. Ini memastikan bahwa kami memiliki panjang minimum C. Urutan kendala dalam sdipilih dengan cermat sehingga pencarian akan memakan waktu terbatas untuk setiap kemungkinan panjang kandidat C; Adibatasi oleh C(kita tidak tahu C, tetapi kita tahu nilai target yang kita miliki untuk panjangnya), Moleh A, Uoleh A, dan Loleh U, sehingga tidak ada pencarian yang dapat memakan waktu tanpa batas.

Saat dekompresi, kami diberikan Clangsung oleh pengguna. Ini lagi memastikan program akan berjalan dalam waktu yang terbatas, karena urutan kendala yang sama. (Orang-orang yang mengetahui urutan evaluasi Prolog akan mencatat bahwa definisi ssangat tidak efisien ketika dekompresi; penempatan length(A,M)dan length(U,L)pertama akan lebih cepat, tetapi pindah length(A,M)ke awal dapat menyebabkan loop tak terbatas ketika dikompresi karena tidak Ajuga Mtidak terikat oleh apa pun pada saat itu) .)


sumber
13

Brachylog , 50 46 byte

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

Cobalah online!

Dekompresi:

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

Cobalah online!

Disimpan 5 byte berkat @ ais523

Penjelasan

Sisi baik dari bahasa deklaratif adalah kita dapat menggunakan kembali kode yang sama untuk mengompresi dan mendekompresi. Dengan demikian, kode untuk kompres sama persis dengan untuk dekompresi , dengan tambahan ~di awal.

Ini ~memberitahu Brachylog untuk membalik urutan argumen (yaitu, gunakan Input sebagai output dan Output sebagai input). Karena kompres tidak ada ~, itu benar-benar menjalankan predikat dalam urutan standar. Karena dekompresi hanya memiliki satu, ia menjalankannya dengan Input sebagai output dan Output sebagai input.

Dengan begitu, kita bisa menggunakan kode yang sama (modulo ekstra ~) untuk kompres dan dekompresi: kompres menyediakan dua string sebagai input dan variabel sebagai output, dan dekompresi menyediakan indeks dan string terkompresi sebagai output dan variabel sebagai input .

Jelas ini juga berarti bahwa kita harus sedikit eksplisit tentang kode kompresi kita, sehingga penerjemah mampu menjalankannya "mundur". Inilah sebabnya mengapa kompresor itu sendiri agak panjang.

Berikut ini adalah rincian kode untuk Kompres (dan karenanya juga dari dekompresi):

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

Jelly , 58 50 byte

-1 byte terima kasih kepada ais523 (gunakan untuk string dua byte)

Ini mungkin cukup golf ...

Kompresi mengambil dua argumen string dan mengembalikan daftar:
[[[startA, lengthA], [startB, lengthB]], compressedString]

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

Dekompresi mengambil satu argumen (daftar seperti itu) dan mengembalikan dua * string:

,
⁾ṫḣżFv
Ḣç€Ṫ

Kode yang tumpang tindih:

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

Diindeks satu.

* ini mungkin tidak jelas karena pemformatan cetak implisit Jelly, jadi kode di TryItOnline yang ditautkan ke atas memiliki byte tambahan (a Ydi bagian akhir) untuk menyisipkan feed garis antara keduanya dalam output yang dicetak.

Saya mulai dengan satu program, yang menggunakan kedalaman argumen pertama (atau satu-satunya) untuk memutuskan antara kompresi dan dekompresi, tetapi memiliki tautan yang tidak digunakan dalam kode dekompresi (baris pertama) dan satu byte tumpang tindih tunggal lebih pendek sebesar tujuh byte .

Bagaimana?

ç;ç@ÑẠ$Ð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
sumber
“ṫḣ”dapat di-golf dengan 1 byte menggunakan sintaks Jelly untuk string 2-karakter.
Ini adalah pertanyaan yang sama sekali tidak terkait dengan jawaban itu sendiri, tetapi apakah Anda menulis penjelasan kode dengan tangan atau apakah ada alat yang menghasilkannya dari kode?
tfrascaroli
@ tfrascaroli Saya menulisnya dengan tangan
Jonathan Allan