ใครอยากเป็น Kolmogorov ผู้ชนะที่ซับซ้อน


22

ภารกิจของคุณในวันนี้คือการประดิษฐ์เครื่องอัดข้อความ

งาน

คุณจะเขียนสองฟังก์ชั่น:

  • ตัวแบ่งบรรจุเป็นฟังก์ชันที่ยอมรับสตริงของอักขระ ASCII (U + 0000 ถึง U + 007F) และส่งออกสตริง Unicode (U + 0000 ถึง U + 10FFFF) ซึ่งมีอักขระน้อยที่สุดเท่าที่จะเป็นไปได้

  • โปรแกรมเปิดไฟล์เป็นฟังก์ชั่นที่ยอมรับสตริงเข้ารหัส Unicode และผลตรงสตริง ASCII เดิม

อินพุต

อินพุตที่ได้รับอนุญาตเท่านั้นคือสตริง ASCII (สำหรับผู้หีบห่อ) และสตริง Unicode ที่บรรจุ (สำหรับผู้แยกบรรจุ) ไม่มีการป้อนข้อมูลของผู้ใช้ไม่มีการเชื่อมต่ออินเทอร์เน็ตไม่ใช้ระบบไฟล์

ฟังก์ชั่นของคุณสามารถเข้าถึงรายการคำศัพท์ภาษาอังกฤษนี้ คุณสามารถใช้รายการนี้เป็นไฟล์ txt ท้องถิ่นหรือคัดลอกเนื้อหาในรหัสต้นฉบับของคุณเป็นสตริงหรืออาร์เรย์ของสตริง

คุณไม่สามารถถอดรหัสโค้ดด้านล่างในฟังก์ชั่นของคุณได้

เอาท์พุต

เอาต์พุตที่ได้รับอนุญาตเท่านั้นสำหรับทั้งสองฟังก์ชันคือสตริง

เอาต์พุตของ unpacker จะต้องมีตัวอักษรเหมือนกับอินพุตของผู้แบ่งบรรจุ

อินพุตและเอาต์พุตของคุณสามารถใช้การเข้ารหัสอักขระที่สนับสนุน Unicode ทั้งหมด (UTF-8/16/32, GB18030, ... ) เนื่องจากคะแนนของคุณจะขึ้นอยู่กับจำนวนของอักขระ Unicode ในเอาต์พุต โปรดระบุรหัสที่คุณใช้อย่างแม่นยำ

หากต้องการนับจำนวนอักขระ Unicode ในเอาต์พุตของคุณคุณสามารถใช้เครื่องมือนี้: http://mothereff.in/byte-counter

เกณฑ์การให้คะแนน

ข้อมูลของคุณจะต้องสามารถแพ็คและแกะตัวอย่างข้อความ 10 ข้อความต่อไปนี้ (ที่ฉันทำในฟอรัมนี้)

คะแนนของคุณจะเป็นผลรวมของขนาดของ 10 สตริงที่บรรจุ (ในอักขระ Unicode) + ขนาดของทั้งสองฟังก์ชันของคุณ (ในอักขระ Unicode ด้วย)

อย่านับขนาดของพจนานุกรมถ้าคุณใช้

โปรดระบุ "คะแนน" ของข้อมูลโค้ดและรุ่นที่บรรจุ

คะแนนต่ำสุดชนะ

ข้อมูล

นี่คือตัวอย่างข้อมูลที่จะเข้ารหัสเพื่อคำนวณคะแนนของคุณ:

1: เนื้อเพลง Rick Roll (1870b): เราไม่มีคนแปลกหน้าในการตีกอล์ฟคุณรู้กฎและฉันก็เช่นกัน

เราไม่ใช่คนแปลกหน้าที่จะรัก
คุณรู้กฏแล้ว
ความมุ่งมั่นอย่างเต็มที่คือสิ่งที่ฉันคิด
คุณจะไม่ได้สิ่งนี้จากคนอื่น
ฉันแค่อยากจะบอกคุณว่าฉันรู้สึกอย่างไร
ต้องทำให้คุณเข้าใจ

อย่ายอมแพ้
อย่าปล่อยให้คุณผิดหวัง
อย่าวิ่งไปรอบ ๆ แล้วละทิ้งคุณ
อย่าทำให้คุณร้องไห้
ไม่เคยบอกลา
อย่าโกหกและทำร้ายคุณ

เรารู้จักกันมานาน
หัวใจของคุณเจ็บปวด แต่
คุณอายเกินกว่าจะพูดได้
ข้างในเราทั้งคู่รู้ว่าเกิดอะไรขึ้น
เรารู้เกมและเราจะเล่น
และถ้าคุณถามฉันว่าฉันรู้สึกอย่างไร
อย่าบอกฉันว่าคุณตาบอดเกินไปที่จะเห็น

อย่ายอมแพ้
อย่าปล่อยให้คุณผิดหวัง
อย่าวิ่งไปรอบ ๆ แล้วละทิ้งคุณ
อย่าทำให้คุณร้องไห้
ไม่เคยบอกลา
อย่าโกหกและทำร้ายคุณ

อย่ายอมแพ้
อย่าปล่อยให้คุณผิดหวัง
อย่าวิ่งไปรอบ ๆ แล้วละทิ้งคุณ
อย่าทำให้คุณร้องไห้
ไม่เคยบอกลา
อย่าโกหกและทำร้ายคุณ

(โอ้โหยอมแพ้)
(โอ้โหยอมแพ้)
(Ooh)
ไม่เคยให้ไม่เคยจะให้
(ยอมแพ้คุณ)
(Ooh)
ไม่เคยให้ไม่เคยจะให้
(ยอมแพ้คุณ)

เรารู้จักกันมานาน
หัวใจของคุณเจ็บปวด แต่
คุณอายเกินกว่าจะพูดได้
ข้างในเราทั้งคู่รู้ว่าเกิดอะไรขึ้น
เรารู้เกมและเราจะเล่น

ฉันแค่อยากจะบอกคุณว่าฉันรู้สึกอย่างไร
ต้องทำให้คุณเข้าใจ

อย่ายอมแพ้
อย่าปล่อยให้คุณผิดหวัง
อย่าวิ่งไปรอบ ๆ แล้วละทิ้งคุณ
อย่าทำให้คุณร้องไห้
ไม่เคยบอกลา
อย่าโกหกและทำร้ายคุณ

อย่ายอมแพ้
อย่าปล่อยให้คุณผิดหวัง
อย่าวิ่งไปรอบ ๆ แล้วละทิ้งคุณ
อย่าทำให้คุณร้องไห้
ไม่เคยบอกลา
อย่าโกหกและทำร้ายคุณ

อย่ายอมแพ้
อย่าปล่อยให้คุณผิดหวัง
อย่าวิ่งไปรอบ ๆ แล้วละทิ้งคุณ
อย่าทำให้คุณร้องไห้
ไม่เคยบอกลา
อย่าโกหกและทำร้ายคุณ

2: The Golfer (412b): การเล่นกอล์ฟ ASCII-art

      '\ . |> 18 >>
        \. ' |
       O >> 'o |
        \. |
        / \ |
       / /. ' |
 JGS ^^^^^^^ `^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^

3: จำนวนเพชร (233b): พิมพ์เพชรนี้

        1
       121
      12321
     1234321
    123454321
   12345654321
  1234567654321
 123456787654321
12345678987654321
 123456787654321
  1234567654321
   12345654321
    123454321
     1234321
      12321
       121
        1

4: ตัวอักษรสี่ครั้ง (107b): พิมพ์ตัวอักษรสี่ครั้ง

ABCDEFGHIJKLMNOPQRSTUVWXYZ
qwertyuiopasdfghjklzxcvbnm
pyfgcrlaoeuidhtnsqjkxbmwvz
zyxwvutsrqponmlkjihgfedcba

5: เนื้อเพลงของ Old McDonald (203b): ฟังก์ชั่น Old MacDonald

Old MacDonald มีฟาร์ม EIEIO
และในฟาร์มนั้นเขามีวัว EIEIO
ด้วยหมู่หมู่ที่นี่และหมู่หมู่ที่นั่น
ที่นี่หมู่ที่มีหมู่ทุกที่หมู่หมู่
Old MacDonald มีฟาร์ม EIEIO!

6: ร็อคตลอดเวลาเนื้อเพลง (144b): ร็อครอบนาฬิกา

1, 2, 3 นาฬิกา, 4 โมงเย็น,
5, 6, 7 โมง, 8 โมงเย็น,
9, 10, 11 โมง, 12 โมงเย็น,
คืนนี้พวกเราจะเขย่าตลอดเวลา

7: Hello World (296b): พูดว่า "Hello" ต่อโลกในรูปแบบ ASCII

 _ _ _ _ _ _ _ _
| | | | ___ | | | ___ __ _____ _ __ | | __ | | |
| | _ | | / _ \ | | / _ \ \ \ / \ / / _ \ | '__ | | / _` | |
| _ | __ / | | (_) | \ VV / (_) | | | | (_ | | _ |
| _ | | _ | \ ___ | _ | _ | \ ___ () \ _ / \ _ / \ ___ / | _ | | _ | \ __ _ (_)
                    | /

8: การอวยพรชาวไอริช (210b): การอวยพรของชาวไอริช

ขอให้ถนนลุกขึ้นเพื่อพบคุณ
ขอให้ลมพัดอยู่ข้างหลังคุณเสมอ
ขอให้แสงอาทิตย์ส่องแสงอุ่นบนใบหน้าของคุณ
ฝนตกลงมาบนทุ่งของคุณ
และจนกว่าเราจะพบกันอีกครั้ง
ขอพระเจ้าทรงโอบกอดคุณไว้ในอุ้งมือของพระองค์

9: มีหญิงชราคนหนึ่งเนื้อเพลง (1208b): มีหญิงชราคนหนึ่ง

มีหญิงชราที่กลืนกินแมลงวัน  
ฉันไม่รู้ว่าทำไมเธอกลืนลงไป  
บางทีเธออาจจะตาย

มีหญิงชราคนหนึ่งที่กลืนกินแมงมุม  
ที่บิดและงอและกระตุกอยู่ภายในเธอ  
เธอกลืนไปเดอร์เพื่อจับแมลงวัน  
ฉันไม่รู้ว่าทำไมเธอกลืนลงไป  
บางทีเธออาจจะตาย

มีหญิงชราคนหนึ่งกลืนนก  
ช่างเป็นเรื่องไร้สาระที่จะกลืนนก  
เธอกลืนนกไปจับแมงมุม  
เธอกลืนไปเดอร์เพื่อจับแมลงวัน  
ฉันไม่รู้ว่าทำไมเธอกลืนลงไป  
บางทีเธออาจจะตาย

มีหญิงชราที่กลืนแมว  
ลองนึกภาพว่าการกลืนแมว  
เธอกลืนแมวไปจับนก  
เธอกลืนนกไปจับแมงมุม  
เธอกลืนไปเดอร์เพื่อจับแมลงวัน  
ฉันไม่รู้ว่าทำไมเธอกลืนลงไป  
บางทีเธออาจจะตาย

มีหญิงชราคนหนึ่งกลืนสุนัข  
ช่างเป็นหมูที่จะกลืนสุนัข  
เธอกลืนสุนัขไปจับแมว  
เธอกลืนแมวไปจับนก  
เธอกลืนนกไปจับแมงมุม  
เธอกลืนไปเดอร์เพื่อจับแมลงวัน  
ฉันไม่รู้ว่าทำไมเธอกลืนลงไป  
บางทีเธออาจจะตาย

มีหญิงชราคนหนึ่งกลืนม้า  
เธอเสียชีวิตแน่นอน

10: ที่อยู่ gettysburg (1452b): วิธีสุ่มคือที่อยู่ Gettysburg

สี่คะแนนและเจ็ดปีที่แล้วบรรพบุรุษของเราได้นำพาชาติใหม่เข้ามาในทวีปนี้โดยตั้งครรภ์ในเสรีภาพ ตอนนี้เรามีส่วนร่วมในสงครามกลางเมืองที่ยิ่งใหญ่ทดสอบว่าประเทศนั้นหรือประเทศใดก็ตามที่รู้สึกและอุทิศตนสามารถยืนยาวได้ เราพบกันในสนามรบที่ยิ่งใหญ่ของสงครามนั้น เรามาอุทิศส่วนหนึ่งของทุ่งนั้นเป็นสถานที่พำนักแห่งสุดท้ายสำหรับผู้ที่ให้ที่นี่ให้ชีวิตของพวกเขาเพื่อชาตินั้นอาจมีชีวิตอยู่ เป็นสิ่งที่เหมาะสมและเหมาะสมที่เราควรทำ แต่ในความหมายที่ใหญ่กว่าเราไม่สามารถอุทิศเราไม่สามารถอุทิศเราไม่สามารถทำให้พื้นดินนี้ศักดิ์สิทธิ์ ชายผู้กล้าหาญทั้งที่มีชีวิตและตายซึ่งดิ้นรนอยู่ที่นี่ได้อุทิศตนให้เหนือกว่าพลังอันต่ำต้อยของเราในการเพิ่มหรือเบี่ยงเบน โลกใบนี้จะโน้ตเล็ก ๆ น้อย ๆ และจำไม่ได้ว่าเราพูดอะไรที่นี่ แต่มันไม่มีวันลืมสิ่งที่พวกเขาทำที่นี่ มันเป็นชีวิตของเราแทนที่จะอุทิศให้กับงานที่ยังไม่เสร็จซึ่งผู้ที่ต่อสู้ที่นี่มีความก้าวหน้าอย่างสูงส่ง เป็นการดีที่เราจะอุทิศตนเพื่องานอันยิ่งใหญ่ที่เหลืออยู่ต่อหน้าเรา - จากความตายที่ได้รับเกียรติเหล่านี้เราได้อุทิศตนให้กับสิ่งที่พวกเขาให้การอุทิศตนอย่างเต็มรูปแบบครั้งสุดท้าย - ว่าเราอยู่ที่นี่อย่างมาก ได้ตายอย่างไร้ค่าซึ่งประเทศนี้ภายใต้พระเจ้าจะมีการเกิดใหม่ของเสรีภาพ - และรัฐบาลของประชาชนโดยประชาชนเพื่อประชาชนจะไม่พินาศไปจากโลก

ทั้งหมด (ไม่บีบอัด): 6135 ตัวอักษร / ไบต์

มีความสุข!


7
นี่ไม่ใช่ความท้าทายในการประดิษฐ์ภาษานี่เป็นความท้าทายในการบีบอัดบางสิ่ง
Justin

2
ฉันคิดว่าการไม่รวมขนาดของคอมไพเลอร์ / ผู้ปฏิบัติการ (คอมเพรสเซอร์ / ตัวขยายการบีบอัด) ในคะแนนทำให้ความท้าทายนี้สิ้นสุดลงเล็กน้อย ในบางจุดเส้นแบ่งระหว่างพจนานุกรมและการเข้ารหัสยากจะบางมาก
Dennis

2
Darn และที่นี่ฉันพิมพ์อยู่แล้ว private static final String RICK_ROLL_RETURN = "We're no strangers to love...
กราฟทฤษฎี

1
ฉันไม่คิดว่าคุณพูดถึงการสังเกตของเดนนิส
Peter Taylor

1
@xem ฉันคิดว่าโพสต์สามารถปรับปรุงได้โดยการจัดระเบียบข้อมูลในส่วนต่างๆเช่น #Task, #Input, #Output, #Scoring ฉันคิดว่าขนาดของซอร์สโค้ดสำหรับคอมเพรสเซอร์และตัวบีบอัดควรรวมอยู่ในคะแนนด้วย สิ่งนี้ไม่ได้ทำร้ายอะไร แต่มันแก้ปัญหาเดนนิสชี้ให้เห็น
Rainbolt

คำตอบ:


6

Haskell - 5322 คะแนน

ไบต์ของรหัส: 686

ขนาดดั้งเดิม: 6147 = 1871+415+234+108+204+145+297+211+1209+1453

ขนาดที่เข้ารหัส: 4636 = 1396+233+163+92+153+115+197+164+979+1144

คะแนน: 686+ 4636

การบีบอัดการนับตัวละคร: ~25%

รหัส

การปรับให้เหมาะสมนอกจากนี้ยังเก็บค่าระหว่าง0และ7fในอักขระ Unicode เป็นปัจจัยสำคัญของพวกเขา

ไม่ลดจำนวนไบต์ของเอาต์พุตที่เข้ารหัส แต่จะลดจำนวนอักขระยูนิโค้ดเท่านั้น ยกตัวอย่างเช่นการทดสอบ # 4 ประกอบด้วยตัวอักษรและการส่งออกที่เข้ารหัส108 92ขนาดที่เกี่ยวข้องมีขนาด108และ364ไบต์

import Data.Bits
import Data.List
import Data.Numbers.Primes
import qualified Data.Text as T
a=nub$concat$map(primeFactors)[0..127]
d(a:r)c=let s=shift c 5in if s<=0x10ffffthen d r(s+a)else c:d r a
d[]c=[c]
f(a:r)=let o=a.&.0x1fin(if o/=a then f((shiftR a 5):r)else f r)++[o]
f[]=[]
g=T.pack.map(toEnum).(\(a:r)->d r a).concatMap j.map(map(\x->head$elemIndices x a)).map(primeFactors.fromEnum).T.unpack
h=T.pack.map(toEnum.product.map((!!)a)).i.f.reverse.map(fromEnum).T.unpack
i(a:r)=let z=a`clearBit`4;x=if a`testBit`4then(take z$repeat$head r,tail r)else splitAt z r in[fst x]++i(snd x)
i[]=[]
j x@(a:_)=let l=length x in if(take l(repeat a))==x then[l`setBit`4,a]else[l]++x
j[]=[0]

มันทำงานอย่างไร

  • การเข้ารหัส

    1. อักขระแต่ละตัวจะถูกแปลงเป็นตัวเลขเทียบเท่ากันให้โทรไปที่หมายเลขnนี้
    2. nจะถูกแปลงเป็นรายการของปัจจัยสำคัญ, ps.
      • สิ่งอำนวยความสะดวกมันเกิดขึ้นที่ตัวเลข 0 ถึง 127 มี 32 ปัจจัยสำคัญที่พบบ่อย, 1ไม่รวม นี่หมายความว่าปัจจัยสามารถจัดเก็บเป็นดัชนีได้เพียง 5 บิต
      • 1 เป็นกรณีพิเศษและแสดงโดยรายการที่ว่างเปล่า
    3. ด้วยpsการเข้ารหัสสามารถเริ่มต้นได้แล้ว
      1. แต่ละจำนวนpsจะถูกแปลงเป็นดัชนีในรายการของ 32 ปัจจัยเฉพาะ (ในรหัสด้านบนรายการนี้จะระบุว่าเป็นa)
      2. (โปรดทราบว่า ณ จุดนี้เรากำลังจัดการกับรายการของดัชนีของปัจจัยสำคัญ) เพื่อดำเนินการในขั้นตอนต่อไปpsจำเป็นต้องแบน เพื่อรักษาความถูกต้องของข้อมูลแต่ละรายการจะถูกแปลงเป็นรายการอื่นของสองส่วน
        1. องค์ประกอบแรกเก็บความยาวของมันและถ้ามันประกอบด้วยปัจจัยเดียวกัน
          • มีปัจจัยสำคัญที่สุด 6 รายการต่อรายการข้อมูลนี้จะถูกเก็บไว้ในบิตขวาสุด 3 รายการ บิตที่ห้าถูกใช้เป็นแฟล็กเพื่อระบุว่ารายการประกอบด้วยปัจจัยเดียวหรือไม่
        2. องค์ประกอบที่เหลือคือดัชนีของตัวเองหรือดัชนีเดี่ยวหากมีปัจจัยที่แตกต่างกันน้อยกว่าสองรายการในรายการ
      3. รายการเหล่านี้จะถูกรวมเข้าด้วยกันเป็นรายการแบบแบนเดียว, fs.
    4. องค์ประกอบของfsสามารถถูกบรรจุเป็นอักขระ Unicode ได้โดยใช้การเลื่อนบิต
  • ถอดรหัส

    • ทำตามขั้นตอนการเข้ารหัสในสิ่งที่ตรงกันข้าม
    • หากคุณกำลังสงสัยว่าพอดีในนี้ผมอยากจะเตือนคุณว่า1product [] == 1

การทดสอบ

การใช้อินเทอร์เฟซนี้สำหรับการทดสอบจะเจ็บปวดดังนั้นฉันจึงใช้ฟังก์ชั่นนี้เพื่อแสดงผลลัพธ์ด้านล่าง

edTest f = do
    t <- readFile f
    let txt = T.pack t
        enc = g txt
        dec = h enc
        tst = txt == dec
    putStrLn $ (show $ T.length txt) ++ "," ++ (show $ T.length enc) ++ "," ++ (show $ T.length dec)++","++(show tst)
    putStrLn $ if not tst then T.unpack txt ++ "\n---NEXT---\n" ++ T.unpack dec else ""


λ> edTest "1"
1871,1396,1871,True

λ> edTest "2"
412,233,412,True

λ> edTest "3"
234,163,234,True

λ> edTest "4"
108,92,108,True

λ> edTest "5"
204,153,204,True

λ> edTest "6"
145,115,145,True

λ> edTest "7"
297,197,297,True

λ> edTest "8"
211,164,211,True

λ> edTest "9"
1209,979,1209,True

λ> edTest "10"
1453,1144,1453,True

ตัวอย่าง

ผลลัพธ์ของฟังก์ชั่นการเข้ารหัสgสำหรับการทดสอบ # 4 คือสิ่งนี้
"\99429\582753\135266\70785\35953\855074\247652\1082563\68738\49724\164898\68157\99429\67973\1082404\587873\73795\298017\330818\198705\69861\1082435\595009\607426\36414\69873\855074\265249\346275\67779\68738\77985\1082513\821353\132131\101410\247652\1082562\49724\164898\67649\594977\34915\67746\50273\135265\103997\563265\103457\1086021\99399\584802\70753\73889\34882\582722\411459\67779\68740\1084516\1082563\1091681\103491\313282\49724\164897\68705\135741\69858\50241\607426\35905\608421\1082435\69858\50274\71777\43075\298018\280517\1082404\67971\36017\955425\67665\919600\100452\132129\214883\35057\856097\101474\70753\135737"
หรือหากคุณเป็นผู้มีความสามารถในการพูดพล่อยๆนี้
𘑥򎑡𡁢𑒁豱󐰢𼝤􈓃𐲂숼𨐢𐨽𘑥𐦅􈐤򏡡𒁃񈰡񐱂𰠱𑃥􈑃򑑁򔓂踾𑃱󐰢񀰡񔢣𐣃𐲂𓂡􈒑󈡩𠐣𘰢𼝤􈓂숼𨐢𐡁򑐡衣𐢢쑡𡁡𙘽򉡁𙐡􉉅𘑇򎱢𑑡𒂡衂򎑂񤝃𐣃𐲄􈱤􈓃􊡡𙑃񌟂숼𨐡𐱡𡈽𑃢쑁򔓂豁򔢥􈑃𑃢쑢𑡡ꡃ񈰢񄟅􈐤𐦃貱󩐡𐡑󠠰𘡤𠐡𴝣裱󑀡𘱢𑑡𡈹

หมายเหตุเพิ่มเติม

  • การใช้http://mothereff.in/byte-counterรายชื่อไดเรกทอรีและedTestขนาดของการทดสอบนั้นมีความสอดคล้องกัน แต่ก็ยังแตกต่างจากขนาดที่ระบุในคำถาม
  • ทดสอบ # 10 มีคู่ของขีดคั่น EM (ก) ที่ฉันแทนที่ด้วย-เนื่องจากพวกเขามีที่อยู่นอก0- 7fช่วง
  • การบีบอัดเพิ่มเติมสามารถทำได้โดยใช้บิตที่สี่ที่เหลือในขณะที่แบนตัวอย่างเช่น00กรณีฐาน01ทำซ้ำทั้งหมด10ทำซ้ำยกเว้นที่ผ่านมา11ทำซ้ำยกเว้นที่ผ่านมา
  • ไฟล์ทดสอบและรหัสมีอยู่ที่นี่https://github.com/gxtaillon/codegolf/tree/master/Kolmogorov

สวัสดีขอบคุณสำหรับคำตอบนี้! :) ฉันไม่เข้าใจว่าเกิดอะไรขึ้นในไบนารี่เมื่อคุณแปลงabcdefghijklm...เป็น𘑥򎑡𡁢𑒁豱󐰢𼝤...คุณช่วยอธิบายหน่อยได้ไหม? นอกจากนี้ฉันได้แก้ไขการนับถ่านและแปลงเครื่องหมายขีดกลางใน # 10 ในคำถาม จำนวนถ่านของฉันยังคงแตกต่างจากของคุณแม้ว่า Dunno ทำไมฉันถึงใช้เครื่องมือ mothereff.in
xem

@xem มีการเปิดเผยรายละเอียดที่ซับซ้อน
gxtaillon

ใจของฉันคือ (เปรียบเปรย) ที่ถูกเป่าโดยความคิดที่ว่าตัวเลข 0 และ 2-127 สามารถเข้ารหัสได้ใน 5 บิต คุณพบสิ่งนี้ด้วยตัวเองหรือเป็นที่รู้จักกันบ้างไหม? คำถามโบนัส: คุณต้องเก็บกี่อักขระ ASCII ที่สามารถพิมพ์ได้เท่านั้นเช่น 95 ตัวอักษรที่แตกต่างกันอย่างไร
xem

@xem ตัวเลขไม่ถูกเข้ารหัสบน 5 บิตแต่ละปัจจัยมี ฉันจะมีความสุขมากถ้าฉันพบวิธีการเข้ารหัส 7 บิตใน 5 เท่านั้นสำหรับอักขระ ascii โดยใช้วิธีนี้พวกเขาจะยังคงต้องการ 5 บิตแต่ละตัว
gxtaillon

1
เนื่องจากในช่วงที่คุณระบุมีปัจจัยมากที่สุด 6 ตัวต่อหมายเลขความยาวใช้ 3 "บล็อก" 5 บิต จากนั้นดัชนีจะถูกเข้ารหัสใน 5 บิตใช่ ในการใช้งานนี้หนึ่งใน 2 บิตที่ไม่ได้ใช้ในบล็อกความยาวจะถูกใช้เพื่อรับการบีบอัดเพิ่มเติม
gxtaillon

4

C ++ (C ++ 11) 2741 คะแนน

คำตอบนี้ใช้ UTF-32 เป็นการเข้ารหัสข้อความที่ถูกบีบอัด

#include <cstdio>
#include <iostream>
#include <locale>
#include <string>
#define L locale
using namespace std;long b,n,i,l;void c(){string d;char x;while((x=cin.get())!=EOF)d+=x;b=(d.size()*7)%20;n=5;wcout.imbue(L());for(char y:d){b=b<<7|y&127;n+=7;if(n>=20)wcout.put(b>>(n-=20)&0xFFFFF);}if(n)wcout.put(b<<20-n&0xFFFFF);}void d(){wstring d;wchar_t w;wcin.imbue(L());while((w=wcin.get())!=EOF)d+=w;l=-1;for(wchar_t y:d){b=b<<20|y;n+=20;if(l<0)l=b>>15&31,n-=5;while(n>=7&(i<d.size()-1|n>20-l))cout.put(b>>(n-=7)&127);++i;}}int main(int t,char**a){L::global(L("en_US.utf8"));**++a<'d'?c():d();}

ถ่านนับและให้คะแนน

รหัส: 593 ตัวอักษร (ขึ้นบรรทัดใหม่ตามรอย)

ข้อความที่ถูกบีบอัด (อักขระ Unicode) : 654 + 145 + 82 + 38 + 51 + 104 + 73 + 423 + 506 = 2148 (นับด้วยwc -mจำนวนอักขระ Unicode แทนที่จะเป็นไบต์จำนวนไบต์จะเท่ากับคำตอบของ @ gxtaillon รวมสูงกว่าต้นฉบับ 8413 ไบต์ทั้งหมดตามที่นับด้วยwc -c)

อัตราส่วนการบีบอัด (ASCII ถึง unicode) : 35.01% (ใช้ 6135 ไบต์จากคำถาม (เหมือนwc -c))

ระวัง:

เชลล์จำนวนมากไม่สามารถจัดการกับอักขระยูนิโค้ดที่โปรแกรมนี้สร้าง ดังนั้นการคลายการบีบอัดอาจนำไปสู่ข้อความที่ถูกตัดออกเมื่อเชลล์ไม่สามารถจัดการอักขระได้เนื่องจากอินพุตถูกstdinดึงผ่านจากเชลล์

การรวบรวม

ควรคอมไพล์ด้วยclang++และg++ -std=c++11, แต่มันจะแสดงคำเตือนบางอย่างเกี่ยวกับลำดับความสำคัญของโอเปอเรเตอร์, เนื่องจากนิพจน์เช่นb<<20-n&0xFFFFFนั้นจะไม่ได้รับการปฏิบัติ((b << 20) - n) & 0xFFFFFเหมือนอย่างที่คาด(b << (20 - n)) & 0xFFFFFไว้

การใช้

  • ./compressรวบรวมโปรแกรมลงในปฏิบัติการเช่น
  • เรียกใช้โปรแกรมเป็น./compress cบีบอัดหรือ./compress dเพื่อขยาย (ระวังการออกจากตัวเลือกจะให้SEGFAULT (การตรวจสอบข้อผิดพลาดมีราคาแพงมาก ... ) และตัวเลือกอื่น ๆ (เช่นใช้Dแทนd) อาจให้ผลลัพธ์ที่ไม่คาดคิด
  • อินพุตถูกอ่านจากstdinและเอาต์พุตที่เขียนลงในstdout

มันทำงานอย่างไร

Ungolfed

#include <cstdio>
#include <iostream>
#include <locale>
#include <string>

using namespace std;

long b, n, i, l;

// Compress
void c() {
    string d;
    char x;
    // Read from STDIN until EOF
    while((x = cin.get()) != EOF)
        d += x;
    // Calculate the number of bits used from the last unicode character
    // (maximum 19) and store it into the first 5 bits
    b = (d.size() * 7) % 20;
    n = 5;
    // Set the output locale to allow unicode
    wcout.imbue(locale());
    // For each character in the input...
    for (char y : d) {
        // Add its bit representation (7 bits) to the right of the buffer
        // by shifting the buffer left and ORing with the character code
        b = (b << 7) | (y & 127);
        // Add 7 to the bit counter
        n += 7;
        // If enough data is present (20 bits per output character),
        // calculate the output character by shifting the buffer right,
        // so that the last 20 bits are the left 20 bits of the buffer.
        // Also decrement the bit counter by 20, as 20 bits are removed.
        if (n >= 20)
            wcout.put((b >> (n -= 20)) & 0xFFFFF);
    }
    // If there are still bits in the buffer, write them to the front of
    // another unicode character
    if (n)
        wcout.put((b << (20 - n)) & 0xFFFFF);
}

// Decompress
void d() {
    wstring d;
    wchar_t w;
    // Set STDIN to UNICODE
    wcin.imbue(locale());
    // Read wide characters from STDIN (std::wcin) until EOF
    while ((w = wcin.get()) != EOF)
        d += w;
    // `l' represents the number of bits used in the last unicode character.
    // It will be set later
    l = -1;
    // For each input character...
    for (wchar_t y : d) {
        // Add it to the buffer and add 20 to the bit counter
        b = (b << 20) | y;
        n += 20;
        // If the number of bits in the last unicode character has not been
        // set yet, read the first 5 buffer bits into `l'. This is
        // necessary because the last character may contain more than 7
        // (one entire uncompressed character) unused bits which may
        // otherwise be interpreted as garbage.
        if (l < 0) {
            l = (b >> 15) & 31;
            n -= 5;
        }
        // As long as there is data to turn into output characters
        // (at least 7 bits in the buffer and either not the last
        // unicode character or before the unused bits)
        while (n >= 7 && ((i < d.size() - 1) || (n > (20 - l)))
            cout.put((b >> (n -= 7)) & 127); // Output the left 7 bits in the buffer as an ASCII character
        ++i; // Increment the character index, so that we know when we reach the last input character
    }
}
int main(int t, char**a) {
    // Set the default locale to en_US.utf8 (with unicode)
    locale::global(locale("en_US.utf8"));
    // Decide whether to compress or decompress.
    // This is just fancy pointer stuff for a[1][0] < 'd' ? c() : d()
    (**(++a) < 'd') ? c() : d();
}

คำอธิบาย

เนื่องจากอนุญาตให้ใช้อักขระ Unicode ได้ตั้งแต่U+0000ถึงU+10FFFFเราจึงสามารถใช้ 20 บิตต่อ Unicode ถ่าน: U+FFFFFใช้ 20 บิตและยังคงรวมอยู่ในช่วงที่อนุญาต ดังนั้นเราจึงพยายามยัดเยียดอักขระ ASCII ทั้งหมดลงในอักขระ Unicode เพื่อเก็บอักขระ ASCII หลายตัวในอักขระ Unicode เพียงตัวเดียว อย่างไรก็ตามเราจำเป็นต้องเก็บจำนวนบิตที่ใช้ในอักขระ Unicode ตัวสุดท้ายเพราะบิตขยะที่ไม่ได้ใช้อาจถูกตีความว่าเป็นอักขระ ASCII ที่ถูกบีบอัดอย่างเหมาะสม เนื่องจากจำนวนบิตสูงสุดที่ใช้ในอักขระ Unicode สุดท้ายคือ 20 เราจะต้องมี 5 บิตซึ่งจะถูกวางไว้ในตำแหน่งเริ่มต้นของข้อมูลที่ถูกบีบอัด

ตัวอย่างผลลัพธ์

นี่คือผลลัพธ์เช่น # 4 (ตามที่กำหนดโดยless):

<U+4E1C5><U+8F265><U+CD9F4><U+69D5A><U+F66DD><U+DBF87><U+1E5CF><U+A75ED>
<U+DFC79><U+F42B8><U+F7CBC><U+BA79E><U+BA77F>쏏𦛏<U+A356B><U+D9EBC><U+63ED8>
<U+B76D1><U+5C3CE><U+6CF8F><U+96CC3><U+BF2F5><U+D3934><U+74DDC><U+F8EAD>
<U+7E316><U+DEFDB><U+D0AF5><U+E7C77><U+EDD7A><U+73E5C><U+786FD><U+DB766>
<U+BD5A7><U+467CD><U+97263><U+C5840>

( 쏏𦛏ให้<U+C3CF><U+266CF>เป็นรหัสตัวละคร แต่ฉันอาจได้รับสิ่งนั้นผิด)


2

Python 3, 289 + 818 = 1107 คะแนน

เพียงกอล์ฟเบา ๆ

import zlib as Z
def p(s):
 z=int.from_bytes(Z.compress(s),'big');o=''
 while z:
  z,d=divmod(z,1<<20)
  if d>0xd000:d+=1<<16
  o+=chr(d)
 return o[::-1]
def u(s):
 i=0
 for c in s:
  d=ord(c)
  if d>0xe000:d-=1<<16
  i=(i<<20)+d
 return Z.decompress(i.to_bytes(i.bit_length()//8+1,'big'))

ขนาดรหัสทั้งหมดคือ 289 ไบต์และเข้ารหัส 6135 ไบต์ที่กำหนดเป็น 818 อักขระ Unicode - จำนวนไบต์เอาต์พุตทั้งหมดคือ 3201 ไบต์ซึ่งมีขนาดเล็กกว่าอินพุตดั้งเดิมอย่างมาก

เข้ารหัสโดยใช้ zlib จากนั้นใช้การเข้ารหัส Unicode เป็นครั้งที่สอง จำเป็นต้องใช้ตรรกะพิเศษบางอย่างเพื่อหลีกเลี่ยงตัวแทน (ซึ่ง Python นั้นเกลียดจริงๆ)

ตัวอย่างเอาต์พุตจาก # 4 ตามที่เห็นless(37 Unicode chars):

x<U+AC0DC><U+BB701><U+D0200><U+D00B0><U+AD2F4><U+EEFC5>𤆺<U+F4F34>멍<U+3C63A><U+2F62C><U+BA5B6><U+4E70A><U+F7D88><U+FF138><U+40CAE>
<U+CB43E><U+C30F5><U+6FFEF>𥠝<U+698BE><U+9D73A><U+95199><U+BD941><U+10B55E><U+88889><U+75A1F><U+4C4BB><U+5C67A><U+1089A3><U+C75A7>
<U+38AC1><U+4B6BB><U+592F0>ᚋ<U+F2C9B>

โปรแกรมควบคุมสำหรับการทดสอบ:

if __name__ == '__main__':
    import os
    total = 0
    for i in range(1,10+1):
        out = p(open('data/%d.txt'%i,'rb').read())
        total += len(out)
        open('out/%d.bin'%i,'w',encoding='utf8').write(out)
    print(total)
    for i in range(1,10+1):
        out = u(open('out/%d.bin'%i,'r',encoding='utf8').read())
        open('data2/%d.txt'%i,'wb').write(out)

จำนวนไบต์เอาท์พุท:

 607 out/1.bin
 128 out/2.bin
 101 out/3.bin
 143 out/4.bin
 177 out/5.bin
 145 out/6.bin
 186 out/7.bin
 222 out/8.bin
 389 out/9.bin
1103 out/10.bin
3201 total

1
ไม่ใช่ความจริงที่ว่าสิ่งนี้ใช้การบีบอัดไลบรารี่โกง?
Beta Decay

@BetaDecay: มันไม่ได้ จำกัด ว่าในคำถามดังนั้นฉันคิดว่ามันเป็นเกมที่ยุติธรรม
nneonneo

นอกจากนี้คุณต้องมีตัวขยายการบีบอัด
Beta Decay

@BetaDecay: pเป็นผู้บรรจุหีบห่อและuเป็นผู้แยกบรรจุ
nneonneo

1

Python 2 - 1,141 คะแนน

from zlib import *;v=256
def e(b):
 x=0
 for c in compress(b,9):x=(x*v)+ord(c)
 b=bin(x)[2:]
 return "".join(unichr(int("1"+b[a:a+19],2))for a in range(0,len(b),19))
def d(s):
 y=int("".join(bin(ord(a))[3:]for a in s),2);x=""
 while y:y,d=(y/v,chr(y%v));x=d+x
 return decompress(x)

ขนาดโค้ดคือ281ไบต์และเข้ารหัส6135ไบต์เป็น860อักขระ Unicode

มันทำงานอย่างไร:

ในการเข้ารหัส:

  1. บีบอัดสตริงที่จะเข้ารหัส
  2. ตีความสตริงที่บีบอัดเป็นตัวเลขฐาน 256
  3. แปลงตัวเลขเป็นเลขฐานสอง
  4. แยกไบนารีออกเป็นกลุ่ม19บิตเพิ่ม1บิตไปที่จุดเริ่มต้นของแต่ละบิตแล้วแปลงเป็นอักขระ Unicode

การถอดรหัสกลับด้าน

โปรดทราบว่าบางรุ่นหลามสามารถจัดการตัวอักษร Unicode ขึ้นไปและทำให้รหัสนี้จะยก0xFFFFValueError

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.