OOP:面向对象的编程


32

似乎不太适合代码打高尔夫球的鲜为人知的编程范例之一是面向重叠编程(OOP) *。当编写部分相同的代码时,只需将相同的部分重叠并以某种方式记住两条原始代码行的开头,就可以节省许多字节。您的任务是编写两个重叠的程序或函数compressdecompress并遵循以下规范:

*请不要在生产代码中使用。

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),返回两个原始字符串。您只需要处理有效的输入。以下等式适用于所有字符串s1s2

(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>")。由于这是,因此分数越低越好。

例:

假设代码为你的功能compressc=abcd,为代码decompressIS d=efghi。然后compress("c=abcd", "d=efghi")产生收益"c=abcd=efghi"(以及指数,但那些指数不会影响得分),因此得分为length "c=abcd=efghi" = 12

附加规则

  • 本着挑战的精神,您compress和您decompress 必须在至少一个字符上重叠。您可以通过添加注释来轻松实现此目的,但请注意,这样做会增加得分,并且使用内在重叠的代码可能会缩短解决方案。
  • compress并且decompress应该能够处理包含任何可打印ASCII字符以及用于定义compress和的所有字符的字符串decompress
  • 索引可以是零索引或一索引。
  • 您的程序或函数不必实际命名为compressdecompress

可以使用其他命令行参数来运行压缩和解压缩代码吗?
MildlyMilquetoast

当然。您必须提供两个程序,并且站点策略允许对命令行参数进行计数(只要计算在内),因此您可以为每个程序提供不同的命令行参数。
Laikoni

Answers:


25

GNU Prolog,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,因为prefixsuffix不可移植。)

Prolog在这一挑战中具有一个有趣的主要优势。您可以编写一个处理多个调用模式的函数(即,不仅可以为该函数提供输入以获取相应的输出,还可以为该函数提供输出以获取相应的输入)。这样,我们可以定义一个既可以处理压缩又可以解压缩的函数,从而导致105字节的提交,该定义定义了o可以双向运行的函数。(顺便说一句,我主要是将它写为解压缩器-因为它更简单-并且使压缩器“免费”。)通常,我们可以期望Prolog中有一个非常短的程序来完成此任务,即使不是那么糟糕的事实也是如此。在字符串处理方面(无论是缺少的原语,还是有问题的原语都具有非常长的名称)。

的第一个参数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 ? ;

上面对I / O格式的描述也几乎完全是对程序的描述。该程序中根本没有太多内容。唯一的微妙之处在于评估顺序提示。我们需要确保程序不仅使用保证终止的搜索策略,而且还要生成尽可能短的输出字符串。

压缩时,我们从length(C,_)(“ C具有长度”)开始,这是我在许多Prolog和Brachylog答案中使用的技巧;如果这是Prolog所看到的第一件事,它将使它优先考虑减少长度C。这确保我们有一个最小长度Cs严格选择约束条件的顺序,以便对于的每个可能的候选长度,搜索都将花费有限的时间CA受限制C(我们不知道C,但我们确实知道其长度的目标值),MAUAL受限制U,因此任何搜索都不会花费无限的时间。

解压缩时,我们C直接由用户给出。由于相同的约束顺序,这再次确保了程序将在有限的时间内运行。(人民谁知道的Prolog的评估顺序会注意到的定义s解压缩时是非常低效的,将length(A,M)length(U,L)第一是快,但移动length(A,M)到开始可能会导致一个无限循环的压缩,因为无论何时A,也没有M被任何东西在当时的约束)


13

Brachylog50 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}

在线尝试!

@ ais523节省了5个字节

说明

声明性语言的好处是,我们可以在压缩和解压缩中重用相同的代码。因此,用于compress的代码与用于decompress的代码完全相同,并在开头添加了其他代码。~

~告诉Brachylog反转参数的顺序(即,使用Input作为输出,使用Output作为输入)。由于compress没有no ~,因此它实际上以标准顺序运行谓词。由于解压缩只有一个,因此它以输入作为输出并以输出作为输入来运行它。

这样,我们可以使用相同的代码(对extra ~进行模化)进行压缩和解压缩:压缩将两个字符串作为输入,变量作为输出,而解压缩将索引和压缩字符串作为输出,并将变量作为输入。

显然,这也意味着我们必须对压缩代码有所了解,以便解释器能够“向后”运行它。这就是压缩机本身有点长的原因。

这是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上的代码有一个额外的字节(Y末尾为a),以便在打印输出中的两者之间插入换行符。

我从一个程序开始,该程序使用第一个(或唯一一个)参数的深度来决定压缩和解压缩之间的关系,但是解压缩代码(第一行)中有未使用的链接,并且单个重叠字节缩短了七个字节。 。

怎么样?

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

“ṫḣ”通过使用Jelly的2字符字符串语法,可以将1个字节打高尔夫球。

这是一个与答案本身完全无关的问题,但是您是手动编写代码的说明还是有从代码生成代码的工具?
tfrascaroli

@tfrascaroli我亲手写的
乔纳森·艾伦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.