OOP: การเขียนโปรแกรมที่เน้นการทับซ้อนกัน


32

หนึ่งในกระบวนทัศน์การเขียนโปรแกรมที่ไม่ค่อยมีคนรู้จักซึ่งดูเหมือนว่าเหมาะสมสำหรับการเล่นกอล์ฟรหัสคือOverlapping Oriented Programming (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 ใด ๆ ที่พิมพ์เช่นเดียวกับตัวละครทั้งหมดที่คุณใช้ในการกำหนดและcompressdecompress
  • ดัชนีสามารถเป็นศูนย์หรือหนึ่งดัชนี
  • โปรแกรมหรือฟังก์ชั่นของคุณจะได้ไม่ต้องจริงจะตั้งชื่อและcompressdecompress

คุณสามารถใช้อาร์กิวเมนต์บรรทัดคำสั่งที่แตกต่างกันเพื่อให้คุณบีบอัดและคลายรหัสได้หรือไม่?
MildlyMilquetoast

แน่ใจ คุณต้องให้สองโปรแกรมและนโยบายไซต์อนุญาตให้ใช้อาร์กิวเมนต์บรรทัดคำสั่งตราบใดที่มีการนับดังนั้นคุณสามารถกำหนดอาร์กิวเมนต์บรรทัดคำสั่งที่แตกต่างกันสำหรับแต่ละโปรแกรมของคุณ
Laikoni

คำตอบ:


25

อารัมภบท GNU 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ไม่ใช่พกพา)

Prolog มีข้อได้เปรียบที่สำคัญและน่าสนใจสำหรับความท้าทายนี้ คุณสามารถเขียนฟังก์ชั่นเพื่อจัดการกับรูปแบบการโทรหลายรูปแบบ (เช่นคุณสามารถให้ฟังก์ชั่นอินพุตเพื่อรับเอาต์พุตที่สอดคล้องกันเท่านั้นคุณสามารถให้ฟังก์ชั่นเอาต์พุตเพื่อรับอินพุตที่สอดคล้องกันได้) เช่นนี้เราสามารถกำหนดฟังก์ชั่นที่สามารถจัดการทั้งการบีบอัดและการคลายการบีบอัดนำไปสู่การส่ง 105- ไบต์ที่กำหนดฟังก์ชั่นoที่ทำงานทั้งสองวิธีรอบ (บังเอิญฉันส่วนใหญ่เขียนเป็นตัวบีบอัด - มันง่ายกว่า - และได้คอมเพรสเซอร์ "ฟรี") โดยทั่วไปเราคาดหวังว่าโปรแกรมสั้นมากใน Prolog สำหรับงานนี้ถ้าไม่ใช่เพราะมันแย่มาก ที่การจัดการสตริง (ทั้งในแง่ของดั้งเดิมที่ขาดหายไปและในแง่ของดั้งเดิมในคำถามที่มีชื่อยาวชะมัด)

อาร์กิวเมนต์แรกoคือ tuple "abcd"-"deab"ของสตริงเช่น อาร์กิวเมนต์ที่สองมีรูปแบบ"deabcd"-4/6-4/4ดังนี้ นี่คือ tuple ซ้อนกันที่ค่อนข้างเป็นมาตรฐานและหมายความว่าสตริงคือ "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สิ่งอื่น Cเพื่อให้แน่ใจว่าเรามีขั้นต่ำที่มีความยาว ลำดับของข้อ จำกัด ในsการคัดเลือกอย่างระมัดระวังเพื่อให้การค้นหาจะใช้เวลาที่ จำกัด สำหรับแต่ละความยาวผู้สมัครที่เป็นไปได้ของC; Aโดยไม่เป็นธรรมC(เราไม่ทราบCแต่เราจะรู้ค่าเป้าหมายที่เรามีสำหรับความยาวของมัน) MโดยA, UโดยAและLโดยUเพื่อให้ไม่มีการค้นหาอาจใช้เวลาไม่ จำกัด เวลา

เมื่อทำการคลายการบีบอัดเราจะได้รับCโดยตรงจากผู้ใช้ สิ่งนี้ทำให้แน่ใจได้ว่าโปรแกรมจะทำงานในเวลาที่ จำกัด เนื่องจากข้อ จำกัด ในลำดับเดียวกัน (คนที่มีความตระหนักในการสั่งซื้อการประเมินผลการเปิดฉากจะทราบว่าคำนิยามของsจะไม่มีประสิทธิภาพมากเมื่อคลาย; การวางlength(A,M)และlength(U,L)ครั้งแรกที่จะได้เร็วขึ้น แต่ย้ายlength(A,M)ไปเริ่มต้นที่อาจก่อให้เกิดห่วงอนันต์เมื่อบีบอัดเพราะไม่Aว่ามิได้Mถูกผูกไว้จากอะไรในเวลานั้น .)


13

Brachylog , 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 ย้อนลำดับของอาร์กิวเมนต์ (นั่นคือใช้อินพุตเป็นเอาต์พุตและเอาต์พุตเป็นอินพุต) เนื่องจากไม่มีการบีบอัดจึง~เรียกใช้เพรดิเคตตามลำดับมาตรฐาน เนื่องจาก decompress มีเพียงอันเดียวมันจึงรันด้วยอินพุตเป็นเอาต์พุตและเอาต์พุตเป็นอินพุต

ด้วยวิธีนี้เราสามารถใช้รหัสเดียวกัน (โมดูโล่ที่พิเศษ~) ในการบีบอัดและคลายการบีบอัด: การบีบอัดคือการให้ทั้งสองสายเป็นอินพุทและตัวแปรเป็นเอาท์พุทและการบีบอัดจะให้ดัชนีและสตริงบีบอัดเป็นเอาท์พุทและตัวแปรเป็นอินพุต .

เห็นได้ชัดว่านี่ยังหมายความว่าเราจะต้องมีความชัดเจนเล็กน้อยเกี่ยวกับรหัสการบีบอัดของเราเพื่อให้ล่ามสามารถเรียกใช้ "ย้อนกลับ" นี่คือเหตุผลว่าทำไมคอมเพรสเซอร์ถึงค่อนข้างยาว

นี่คือรายละเอียดของรหัสสำหรับการบีบอัด (และยังคลาย):

{……………………………………………………………………}   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 ฉันเขียนด้วยมือ
Jonathan Allan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.