OOP: Програмування, орієнтоване на перекриття


32

Однією з менш відомих парадигм програмування, яка здається досить придатною для гольфу з кодом, є програмування, орієнтоване на перекриття (OOP) *. При написанні частково однакового коду багато байтів можна зберегти, просто перекриваючи однакові частини і певним чином запам'ятовуючи, звідки починаються дві оригінальні лінії коду. Ваше завдання полягає в тому, щоб написати дві пересічні програми або функції compressі decompressз наступними характеристиками:

* Мабуть, не використовуйте у виробничому коді.

compress

compressбере два рядки в будь-якому зручному форматі і максимально перекриває їх. Тобто рядок sз мінімальною довжиною повертається таким чином, що обидва вхідні рядки є підрядками s. Крім того, повертається деякий вихід, який ідентифікує початковий та кінцевий індекси обох рядків.

Приклади: (Точний IO-формат залежить від вас)

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

decompressобчислює зворотну функцію compress, тобто заданий рядок та два індекси початку та кінця (у форматі, в якому вони повертаються вашим compress), поверніть два початкові рядки. Вам потрібно обробляти лише дійсні входи. Рівність має виконуватися для всіх рядків s1, s2:

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

Приклади: (звороти compressприкладів)

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"

Оцінка балів

Ваш бал - це розмір рядка, що повертається дзвінками compress("<code of compress>", "<code of decompress>"). Оскільки це то нижчий бал кращий.

Приклад:

Припустимо, код для вашої функції compressє, c=abcdі код для decompressє d=efghi. Тоді compress("c=abcd", "d=efghi")дохідність "c=abcd=efghi"(і показники, але ті, які не впливають на оцінку), так що оцінка є length "c=abcd=efghi" = 12.

Додаткові правила

  • У дусі цього виклику ваше compressі decompress повинне перекриватися хоча б одним персонажем. Ви можете домогтися цього банально, додавши коментар, але зауважте, що це зробить ваш рахунок і може бути коротшим рішення, використовуючи притаманний коду, що перекривається.
  • compressі decompressповинна мати можливість обробляти рядки, що містять будь-які символи для друку ASCII, а також усі символи, які ви використовували для визначення compressтаdecompress .
  • Індекси можуть бути нульовими або одноіндексованими.
  • Ваші програми або функції насправді не повинні бути названі compressі decompress.

Чи можете ви використовувати різні аргументи командного рядка для запуску стискання та розпакування коду?
MildlyMilquetoast

Звичайно. Ви повинні надати дві програми, і політика сайту дозволяє аргументи командного рядка до тих пір, поки вони рахуються, тому ви можете наводити різні аргументи командного рядка для кожної програми.
Лайконі

Відповіді:


25

ГНУ Пролог, 105 балів

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

(Для цього потрібен GNU Prolog, оскільки prefix і suffixне є переносними.)

Пролог має одну цікаву головну перевагу для цього виклику; ви можете написати функцію для обробки декількох шаблонів викликів (тобто не тільки ви можете надати функції вхід для отримання відповідного виводу, ви можете надати функції вихід для отримання відповідного вводу). Як такий, ми можемо визначити функцію, яка може обробляти як стиснення, так і декомпресію, що призводить до подання 105 байтів, що визначає функціюo яка працює обома способами. (До речі, я здебільшого писав це як декомпресор - як це простіше - і дістав компресор "безкоштовно".) Загалом, ми могли б очікувати на дуже коротку програму в Пролозі для цього завдання, якби не той факт, що це так погано при обробці струн (як з точки зору відсутніх примітивів, так і з точки зору примітивів, про які йдеться, жахливо довгі назви).

Перший аргумент o- це набір рядків, наприклад "abcd"-"deab". Другий аргумент має форму, подібну до одного аргументу, він видасть інший для вас (таким чином, працюючи як компресор, якщо ви дасте перший аргумент, і декомпресор, якщо ви дасте другий). Якщо ви дасте йому обидва аргументи, він перевірить, чи стисне представлення відповідає заданим рядкам. Якщо навести нульові аргументи, він отримає такий результат:"deabcd"-4/6-4/4 ; це досить стандартний вкладений кортеж і означає, що рядок є "deabcd", перша рядок має довжину 4 і закінчується на шостому символі, друга рядок має довжину 4 і закінчується на четвертому символі. (Зауважте, що рядок у GNU Prolog - це лише перелік символьних кодів, що робить налагодження дратівливим, оскільки реалізація надає перевагу останній інтерпретації за замовчуванням.)o

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

Наведений вище опис формату вводу / виводу є майже повністю лише описом програми; взагалі не дуже багато в програмі. Єдина тонкоща - це підказки щодо порядку оцінки; нам потрібно переконатися, що програма не просто використовує стратегію пошуку, яка гарантовано припиняється, але також виробляє найкоротший можливий рядок виводу.

Під час стискання ми починаємо з length(C,_)(" Cмає довжину"), що є хитрістю, яке я використав у багатьох відповідях Пролога та Брахілога; якщо це перше, що бачить Пролог, це змусить його визначити пріоритет скорочення тривалості Cпонад усе. Це гарантує, що у нас мінімальна довжина C. Впорядкування обмежень в sретельному виборі, щоб пошук займав обмежений час для кожної можливої ​​тривалості кандидата C; Aстримується C(ми не знаємо C, але ми знаємо , цільове значення , яке ми маємо для її довжини), Mна A, Uпо A, і Lпо U, так жоден із запитів не може приймати необмежений час.

При розпакуванні нам надається Cбезпосередньо користувач. Це ще раз гарантує, що програма запуститься в обмежений час, завдяки одній послідовності обмежень. (Люди, які знають про порядок оцінки Prolog, відзначають, що визначення sдуже неефективне при розпакуванні; розміщення length(A,M)і length(U,L)спочатку буде швидше, але перехід length(A,M)до початку може спричинити нескінченний цикл при стисненні, оскільки ні на час, Aні Mна що нічого не пов'язане .)


13

Брахілог , 50 46 байт

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

Спробуйте в Інтернеті!

Декомпрес:

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

Спробуйте в Інтернеті!

Збережено 5 байт завдяки @ ais523

Пояснення

Хорошою стороною декларативних мов є те, що ми можемо повторно використовувати один і той же код як для стискання, так і для декомпресії. Як такий, код для стиснення точно такий же, як і для декомпресії , з додатковим ~на початку.

Це ~спонукає Brachylog змінити порядок аргументів (тобто використовувати Input як вихід та Output як вхід). Оскільки компресу немає ~, він фактично запускає присудок у стандартному порядку. Оскільки у декомпресії є лише один, він запускає його з Input як вихід та Output як вхід.

Таким чином, ми можемо використовувати один і той же код (модуль, який є додатковим ~) і для стискання, і для розпакування: стиснення забезпечує два рядки як вхідні, і змінну як вихідну, а розпаковувальна - надає індекси та стислий рядок як вихід і змінна як введення .

Очевидно, це також означає, що ми повинні бути трохи чіткими щодо нашого стискаючого коду, щоб інтерпретатор міг запускати його "назад". Ось чому сам компресор трохи довгий.

Ось розбивка коду для Compress (а отже, і для розпакування):

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

Желе , 58 50 байт

-1 байт завдяки ais523 (використовувати для двобайтового рядка)

Це цілком може бути гольфуючим ...

Стиснення бере два рядкові аргументи і повертає список:
[[[startA, lengthA], [startB, lengthB]], compressedString]

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

Декомпресія бере один аргумент (такий список) і повертає два * рядки:

,
⁾ṫḣżFv
Ḣç€Ṫ

Перекритий код:

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

Одноіндексовані.

* це може бути не очевидним через неявне форматування друку Jelly, тому код у TryItOnline, пов'язаний вище, має додатковий байт (a Yв кінці), щоб вставити канал рядка між двома у друкований вихід.

Я почав з єдиної програми, яка використовувала глибину першого (або єдиного) аргументу для вирішення між стисненням та декомпресією, але маючи невикористане посилання в коді декомпресії (перший рядок) та один байт, що перекривається, коротший на сім байтів .

Як?

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

“ṫḣ”можна пограти на 1 байт, використовуючи синтаксис Jelly для рядків з 2 символами.

Це питання, абсолютно не пов’язане з відповіддю, як таке, але ви пишете пояснення коду вручну чи є інструмент, що генерує його з коду?
tfrascaroli

@tfrascaroli Я пишу це від руки
Джонатан Аллан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.