OOP: Lập trình định hướng chồng chéo


32

Một trong những mô hình lập trình ít được biết đến có vẻ khá phù hợp với việc chơi golf mã là Lập trình định hướng chồng chéo (OOP) *. Khi viết mã giống hệt nhau, nhiều byte có thể được lưu bằng cách chỉ cần chồng chéo các phần giống hệt nhau và ghi nhớ theo một cách nào đó nơi hai dòng mã gốc bắt đầu. Nhiệm vụ của bạn là viết hai chương trình hoặc hàm chồng chéocompressdecompressvới đặc tả sau:

* Có thể không sử dụng trong mã sản xuất.

compress

compresslấy hai chuỗi trong bất kỳ định dạng thuận tiện và chồng chéo chúng càng nhiều càng tốt. Đó là một chuỗi scó độ dài tối thiểu được trả về sao cho cả hai chuỗi đầu vào là chuỗi con của s. Ngoài ra, một số đầu ra xác định các chỉ số bắt đầu và kết thúc của cả hai chuỗi được trả về.

Ví dụ: (Định dạng IO chính xác tùy thuộc vào bạn)

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

decompresstính toán hàm nghịch đảo của compress, được đưa ra một chuỗi và hai chỉ số bắt đầu và kết thúc (theo định dạng mà chúng được trả về bởi bạn compress), trả về hai chuỗi gốc. Bạn chỉ cần xử lý đầu vào hợp lệ. Bình đẳng sau nên giữ cho tất cả các chuỗi s1, s2:

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

Ví dụ: (đảo ngược các compressví dụ)

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"

Chấm điểm

Điểm của bạn là kích thước của chuỗi được trả về bằng cách gọi compress("<code of compress>", "<code of decompress>"). Vì đây là điểm thấp hơn là tốt hơn.

Thí dụ:

Giả sử mã cho chức năng của bạn compressc=abcdvà mã cho decompressd=efghi. Sau đó, compress("c=abcd", "d=efghi")sản lượng "c=abcd=efghi"(và các chỉ số, nhưng những chỉ số này không ảnh hưởng đến việc ghi điểm) vì vậy điểm số là length "c=abcd=efghi" = 12.

Quy tắc bổ sung

  • Theo tinh thần của thử thách này, bạn compressdecompress phải chồng chéo ít nhất một nhân vật. Bạn có thể đạt được điều này một cách tầm thường bằng cách thêm một nhận xét, nhưng lưu ý rằng làm như vậy sẽ tăng điểm của bạn và có thể có các giải pháp ngắn hơn bằng cách sử dụng mã chồng chéo vốn có.
  • compressdecompressphải có khả năng xử lý các chuỗi chứa bất kỳ ký tự ASCII có thể in nào cũng như tất cả các ký tự bạn đã sử dụng để xác định compressdecompress.
  • Các chỉ số có thể bằng 0 hoặc một chỉ mục.
  • Các chương trình hoặc chức năng của bạn không thực sự phải được đặt tên compressdecompress.

Bạn có thể sử dụng các đối số dòng lệnh khác nhau để chạy bạn nén và giải nén mã không?
MildlyMilquetoast

Chắc chắn rồi. Bạn phải đưa ra hai chương trình và chính sách trang web cho phép đối số dòng lệnh miễn là chúng được tính, vì vậy bạn có thể đưa ra các đối số dòng lệnh khác nhau cho mỗi chương trình của mình.
Laikoni

Câu trả lời:


25

GNU Prolog, 105 điểm

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

(Điều này yêu cầu GNU Prolog vì prefixsuffixkhông khả dụng.)

Prolog có một lợi thế lớn, thú vị cho thử thách này; bạn có thể viết một hàm để xử lý nhiều mẫu cuộc gọi (tức là không chỉ bạn có thể cung cấp cho hàm một đầu vào để có đầu ra tương ứng, bạn có thể cung cấp cho hàm một đầu ra để có đầu vào tương ứng). Như vậy, chúng ta có thể định nghĩa một hàm có thể xử lý cả nén và giải nén, dẫn đến đệ trình 105 byte xác định một hàm ohoạt động theo cả hai cách. (Ngẫu nhiên, tôi chủ yếu viết nó như một bộ giải nén - vì nó đơn giản hơn - và có máy nén "miễn phí".) Nói chung, chúng ta có thể mong đợi một chương trình rất ngắn trong Prolog cho nhiệm vụ này, nếu không phải vì nó quá tệ tại xử lý chuỗi (cả về mặt nguyên thủy bị thiếu và về mặt nguyên thủy trong câu hỏi có tên dài khủng khiếp).

Đối số đầu tiên olà một chuỗi các chuỗi, ví dụ "abcd"-"deab". Đối số thứ hai có dạng như "deabcd"-4/6-4/4; đây là một tuple lồng nhau khá chuẩn và có nghĩa là chuỗi là "dablescd", chuỗi thứ nhất có độ dài 4 và kết thúc ở ký tự thứ sáu, chuỗi thứ hai có độ dài 4 và kết thúc ở ký tự thứ tư. (Lưu ý rằng một chuỗi trong GNU Prolog chỉ là một danh sách các mã ký tự, điều này làm cho việc gỡ lỗi trở nên khó chịu vì việc triển khai thích cách giải thích sau theo mặc định.) Nếu bạn đưa raomột đối số, nó sẽ xuất ra đối số khác cho bạn (do đó hoạt động như một máy nén nếu bạn đưa ra đối số đầu tiên và bộ giải nén nếu bạn đưa ra đối số thứ hai). Nếu bạn cung cấp cho cả hai đối số, nó sẽ xác minh rằng biểu diễn nén phù hợp với các chuỗi đã cho. Nếu bạn cung cấp cho nó các đối số bằng không, nó sẽ tạo ra kết quả như thế này:

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

Mô tả ở trên của định dạng I / O gần như hoàn toàn chỉ là một mô tả về chương trình; không có nhiều trong chương trình. Sự tinh tế duy nhất là để làm với gợi ý thứ tự đánh giá; chúng tôi cần đảm bảo rằng chương trình không chỉ sử dụng chiến lược tìm kiếm được đảm bảo để chấm dứt mà còn tạo ra chuỗi đầu ra ngắn nhất có thể.

Khi nén, chúng tôi bắt đầu bằng length(C,_)(" Ccó độ dài"), đây là một mẹo mà tôi đã sử dụng trong nhiều câu trả lời của Prolog và Brachylog; nếu đây là điều đầu tiên Prolog nhìn thấy, nó sẽ khiến nó ưu tiên giảm độ dài của Cbất kỳ thứ gì khác. Điều này đảm bảo rằng chúng tôi có độ dài tối thiểu C. Thứ tự của các ràng buộc trong sđược chọn cẩn thận để việc tìm kiếm sẽ mất một thời gian hữu hạn cho mỗi độ dài ứng cử viên có thể là C; Abị ràng buộc bởi C(chúng tôi không biết C, nhưng chúng tôi biết giá trị mục tiêu chúng tôi có cho chiều dài của nó), Mbởi A, Ubởi A, và Lbởi U, vì vậy không có tìm kiếm nào có thể mất thời gian không giới hạn.

Khi giải nén, chúng tôi được cung cấp Ctrực tiếp bởi người dùng. Điều này một lần nữa đảm bảo chương trình sẽ chạy trong thời gian hữu hạn, do cùng một chuỗi các ràng buộc. (Những người nhận thức được thứ tự đánh giá của Prolog sẽ lưu ý rằng định nghĩa về srất không hiệu quả khi giải nén; đặt length(A,M)length(U,L)trước tiên sẽ nhanh hơn, nhưng di chuyển length(A,M)đến điểm bắt đầu có thể gây ra một vòng lặp vô hạn khi nén bởi vì không phải lúc nào Acũng Mbị ràng buộc bởi bất cứ điều gì .)


13

Brachylog , 50 46 byte

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

Hãy thử trực tuyến!

Giải nén:

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

Hãy thử trực tuyến!

Đã lưu 5 byte nhờ @ ais523

Giải trình

Mặt tốt của các ngôn ngữ khai báo là chúng ta có thể sử dụng lại cùng một mã cho cả nén và giải nén. Như vậy, mã để nén hoàn toàn giống như khi giải nén , với phần bổ sung ~ở đầu.

Điều này báo ~cho Brachylog đảo ngược thứ tự các đối số (nghĩa là sử dụng Đầu vào làm đầu ra và Đầu ra làm đầu vào). Vì nén không có ~, nó thực sự chạy biến vị ngữ theo thứ tự chuẩn. Vì giải nén chỉ có một, nên nó chạy với Đầu vào là đầu ra và Đầu ra là đầu vào.

Bằng cách đó, chúng ta có thể sử dụng cùng một mã (modulo thêm ~) để nén và giải nén: nén đang cung cấp hai chuỗi là đầu vào và một biến là đầu ra, và giải nén là cung cấp các chỉ mục và chuỗi nén làm đầu ra và một biến là Đầu vào .

Rõ ràng điều này cũng có nghĩa là chúng ta phải có một chút rõ ràng về mã nén của mình, để trình thông dịch có khả năng chạy nó "ngược". Đây là lý do tại sao bản thân máy nén hơi dài.

Dưới đây là bảng phân tích mã cho Nén (và do đó cũng là giải nén):

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

Thạch , 58 50 byte

-1 byte nhờ ais523 (sử dụng cho chuỗi hai byte)

Điều này cũng có thể khá golf ...

Nén có hai đối số chuỗi và trả về một danh sách:
[[[startA, lengthA], [startB, lengthB]], compressedString]

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

Giải nén lấy một đối số (như một danh sách) và trả về hai chuỗi *:

,
⁾ṫḣżFv
Ḣç€Ṫ

Mã chồng chéo:

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

Một chỉ mục.

* điều này có thể không rõ ràng do định dạng in ngầm của Jelly, do đó mã tại TryItOnline được liên kết ở trên có thêm một byte (a Yở cuối) để chèn một nguồn cấp dữ liệu giữa hai trong đầu ra được in.

Tôi đã bắt đầu với một chương trình duy nhất, sử dụng độ sâu của đối số đầu tiên (hoặc duy nhất) để quyết định giữa nén và giải nén, nhưng có một liên kết không được sử dụng trong mã giải nén (dòng đầu tiên) và một byte chồng chéo đơn lẻ ngắn hơn bảy byte .

Làm sao?

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

“ṫḣ”có thể được chơi bằng 1 byte bằng cách sử dụng cú pháp của Jelly cho chuỗi 2 ký tự.

Đây là một câu hỏi hoàn toàn không liên quan đến câu trả lời, nhưng bạn có viết lời giải thích về mã bằng tay không hoặc có một công cụ tạo ra nó từ mã không?
tfrascaroli

@tfrascaroli Tôi viết nó bằng tay
Jonathan Allan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.