पैलिंड्रोम संपीड़न


15

चुनौती

एक प्रोग्राम लिखें जो ASCII पाठ को दोषरहित और संकुचित करता है। केस-असंवेदनशील और विराम चिह्न-असंवेदनशील palindromes सहित, यह palindromes के साथ अच्छी तरह से काम करने के लिए विशेष होना चाहिए। सबसे छोटे स्रोत के साथ सबसे अच्छा संपीड़न जीतता है।

स्कोरिंग

total_bytes_saved / sqrt(program_size) - उच्चतम स्कोर जीत

total_bytes_savedनीचे के परीक्षण मामलों में कुल कितने बाइट्स हैं, जो संपीड़ित स्ट्रिंग्स मूल से अधिक हैं। program_sizeसंपीड़न और अपघटन दोनों कार्यक्रमों के स्रोत कोड के बाइट्स में आकार है। दोनों की जरूरत के बीच साझा किए गए कोड को केवल एक बार गिना जाना चाहिए।

उदाहरण के लिए, यदि 10 परीक्षण मामले हैं और 100 बाइट प्रोग्राम में 7 परीक्षण मामलों में 5 बाइट्स बचाए गए हैं, तो उनमें से 2 पर 10, लेकिन अंतिम परीक्षण का मामला 2 बाइट्स लंबा था, समाधान 5.3 स्कोर करेगा। ((7 * 5 + 10 * 2 - 2) / sqrt(100) = 5.3 )

परीक्षण के मामलों

  • tacocat
  • toohottohoot
  • todderasesareddot
  • amanaplanacanalpanama
  • wasitacaroracatisaw?
  • Bob
  • IManAmRegalAGermanAmI
  • DogeeseseeGod
  • A Santa at NASA
  • Go hang a salami! I'm a lasagna hog.

नियम

  1. मानक खामियां लागू होती हैं।
  2. संपीड़न को सभी मुद्रण योग्य ASCII (बाइट्स 32-126, समावेशी) टेक्स्ट स्ट्रिंग्स पर काम करना चाहिए, न कि केवल पैलिंड्रोम्स। यह वास्तव में किसी भी जानकारी के लिए अंतरिक्ष को बचाने के लिए नहीं है, हालांकि।
  3. आउटपुट बाइट्स या वर्णों का कोई भी क्रम हो सकता है, भले ही इसके कार्यान्वयन या आंतरिक प्रतिनिधित्व (स्ट्रिंग, सूचियां और सरणियाँ सभी निष्पक्ष खेल हों, उदाहरण के लिए)। यदि UTF-8 को एन्कोडिंग है, तो बाइट्स की गणना करें, वर्णों की नहीं। वाइड स्ट्रिंग्स (जैसे UTF-16 या UTF-32) को अनुमति नहीं दी जाती है जब तक कि संभवतः उपयोग किए गए एकमात्र कोडपॉइंट्स 0 और 255 के बीच न हों।
  4. संपीड़न / अपघटन निर्मित करने की अनुमति नहीं है।

हमारे अपने आनंद के लिए, अपने स्रोत कोड के साथ संपीड़ित तारों को पोस्ट करें।

अद्यतन 1: बेहतर संपीड़न के लिए अधिक वजन और आक्रामक गोल्फिंग को कम वजन देने के total_bytes_saved / program_sizeलिए स्कोरिंग से बदलाव किया गया total_bytes_saved / sqrt(program_size)। तदनुसार अपने स्कोर समायोजित करें।

अद्यतन 2:wasitacaroraratisaw? होना तय हैwasitacaroracatisaw?


2
यदि मामला, विचलन और रिक्ति को इनपुट से हटा दिया जाता है, तो क्या यह गारंटी है कि इनपुट सख्त पैलिंड्रोम होंगे? संपादित करें: कोई बात नहीं - मैं देख रहा हूँ wasitacaroraratisaw?कि की एक प्रति है
डिजिटल ट्रामा

2
ASCII वर्णों की किस श्रेणी को हम इनपुट में समर्थन करने वाले हैं? क्या यह है [32-126]?
अरनुलद

1
हाँ, मुझे नहीं लगता कि इस 1000 *हिस्से की वास्तव में ज़रूरत है, और नहीं, मुझे नहीं लगता कि यह स्कोर को अधिक "संतोषजनक" महसूस करेगा;)
आउटगॉल्फ

1
क्या हम कम्प्रेशन / डीकंप्रेसन बिल्ट-इन का उपयोग कर सकते हैं?
लिन

4
इतने कम इनपुट के साथ, कुछ भी चालाक करने की बहुत गुंजाइश नहीं है। अच्छा होगा कि कम से कम कुछ गुना अधिक हो।
user1502040

जवाबों:


16

जावास्क्रिप्ट (ईएस 6), 3.143 (81 बाइट्स बचा, 664 बाइट प्रोग्राम)

R='replace',S=String.fromCharCode,T=c=>c.charCodeAt(),U='toUpperCase',V='0000000',W=(a,b,c=2)=>a.toString(c).slice(b),X=x=>'0b'+x,Y=a=>[...a].reverse().join``,Z=/[^]/g
C=s=>S(...((Y(q=s[U]()[R](/[^A-Z]/g,m=''))==q?(q=q.slice(0,p=-~q.length/2),p%1&&10):11)+q[R](Z,x=>W(T(x),2))+111+s[R](Z,c=>/[a-z]/.test(c)?W("00",m,m=1):m+(/[A-Z]/.test(c,m='')?"01":W(c<'!'?2:T(c)+384)))+V).match(/(?!0+$).{8}/g).map(X))
D=s=>{s=s[R](Z,c=>W(256+T(c),1))+V;M=r=>(s=s[R](p=s.match(`^${r}|`)[0],''),p);for([,a]=M`1.|0`,t=u=i='';!M`111`;)t+=W(X(M`.{5}`)-~8,0,36);for(t+=W(Y(t),a?a/0:1);p;)u+=M`0(?=00)|00?1`?(c=t[i++])?+p[1]?c[U]():c:'':M`10`?' ':M`11`&&S(X(M`.{7}`));return u+W(t,i)}

अब जब मैं इस कार्यक्रम (और स्कोरिंग प्रणाली) से काफी संतुष्ट हूं, तो मैं थोड़ा स्पष्टीकरण लिखूंगा।

मूल विचार इनपुट को बिट्स के एक स्ट्रिंग में संपीड़ित करना है, फिर 8 बिट्स के प्रत्येक सेट को बाइट में संपीड़ित करना है। स्पष्टीकरण के प्रयोजनों के लिए, मैं बस थोड़ा स्ट्रिंग में हेरफेर करूँगा।

बिट स्ट्रिंग को कई वर्गों में विभाजित किया जा सकता है:

input  -> Taco Cat.
output -> 0101000000100011011111110100001100100011101011100000000

0      | 10100 00001 00011 01111 111 | 01 00001 10 01 0001 110101110
header | letter data                 | styling data

हेडर एक बहुत ही सरल मैपिंग है:

0  -> odd-length palindrome
10 -> even-length palindrome
11 -> non-palindrome

लेटर डेटा भी काफी सरल है। सबसे पहले, सभी गैर-अक्षर स्ट्रिंग से निकाले जाते हैं, और सभी अक्षरों को अपरकेस में बदल दिया जाता है। यदि परिणामस्वरूप स्ट्रिंग एक palindrome है, तो उलटा आधा छीन लिया जाता है। फिर इस मानचित्रण को लागू किया जाता है:

A -> 00001
B -> 00010
C -> 00011
D -> 00100
...
Z -> 11010

इस अनुभाग को समाप्त कर दिया गया है 111। इसके बाद स्टाइलिंग डेटा आता है, जो अपर / लोअर-केस डेटा और नॉन-लेटर्स को स्टोर करता है। यह इस तरह काम करता है:

01 -> next letter as uppercase
0...01 (n 0s) -> next (n-1) letters as lowercase
10 -> space
11xxxxxxx -> character with code point 0bxxxxxxx

तो ऊपर दिखाए गए उदाहरण के माध्यम से, हमारे पास है

header: 0 -> palindrome
letter data: 10100 00001 00011 01111 111 -> taco
styling data:
  01        -> T
  00001     -> aco
  10        -> <space>
  01        -> C
  0001      -> at
  110101110 -> .

जब बिट स्ट्रिंग का अंत हो जाता है, तो पत्र डेटा से शेष सभी वर्ण परिणाम के लिए जोड़ दिए जाते हैं। यह हमें एक आखिरी करने से बचाता है000...001 और हमें इन बिट्स को स्ट्रिंग से अलग करने की अनुमति देता है।

परीक्षण मामलों के माध्यम से जा रहे हैं:

tacocat -> 3 bytes (-4)
    24 bits: 010100000010001101111111
toohottohoot -> 5 bytes (-7)
    35 bits: 10101000111101111010000111110100111
todderasesareddot -> 7 bytes (-10)
    49 bits: 0101000111100100001000010110010000011001100101111
amanaplanacanalpanama -> 8 bytes (-13)
    59 bits: 00000101101000010111000001100000110000001011100000100011111
wasitacaroracatisaw? -> 11 bytes (-9)
    84 bits: 010111000011001101001101000000100011000011001001111111000000000000000000001110111111
Bob -> 2 bytes (-1)
    16 bits: 0000100111111101
IManAmRegalAGermanAmI -> 13 bytes (-8)
    98 bits: 00100101101000010111000001011011001000101001110000101100111010100010100101000001010100000010100101
DogeeseseeGod -> 7 bytes (-6)
    54 bits: 000100011110011100101001011001100101111010000000000101
A Santa at NASA -> 8 bytes (-7)
    63 bits: 100000110011000010111010100000011110110010000011000011001010101
Go hang a salami! I'm a lasagna hog. -> 20 bytes (-16)
   154 bits: 1000111011110100000001011100011100001100110000101100000010110101001111010011000000110001100000000111010000110011101001110011000110000000001100000111010111

वाह। मैं वास्तव में इस दृष्टिकोण से प्रभावित हूँ। मैंने कभी इस तरह से एक बिट-पैक एन्कोडिंग बनाने के लिए नहीं सोचा होगा। (मैंने ASCII को 7 बिट्स में पैक करने के मामले के बारे में सोचा था, लेकिन palindromes के लिए बहुत जगह नहीं बचाती है) मैं प्रभावित हूं कि आप अंतरिक्ष को भी बचाने में कामयाब रहे Bob
बीफस्टर

4
यह इंजीनियरिंग के मूल सिद्धांतों का एक शानदार उदाहरण है। एक समस्या का वर्णन करना, इसे हल करने के विभिन्न तरीकों के बारे में सोचना और आवश्यकताओं के बीच ट्रेडऑफ़ बनाना (यानी विभिन्न शैलियों को कितने बिट्स समर्पित करना है), आदि
रॉबर्ट फ्रेजर

@Beefster धन्यवाद :-) Bobवास्तव में बस जगह में गिर गया - शीर्ष लेख के लिए 1 बिट, दो अक्षरों के लिए 10 + 3 बिट्स, और एकल अपरकेस अक्षर के लिए 2 बिट्स। अगर मैंने अपनी सबसे कठिन कोशिश की तो इसे कोई छोटा नहीं कर सकता ...
ETHproductions

1
@KevinCruijssen समस्या यह है कि जो चीज़ जोड़ी जा रही है वह एक तार है, इसलिए इसे पहले एक संख्या में बदलना होगा। यह तरीका बाइट से कम है-0+9
ETHproductions

1
@ETHproductions आह (निश्चित रूप से यह एक स्ट्रिंग नहीं था)! +9स्ट्रिंग को -~8समाप्‍त करेगा , जबकि +9अंकगणित करेगा (चूंकि -तार के लिए कुछ भी नहीं करता है, इसलिए यह इसे एक संख्या के रूप में व्याख्या करता है)। उस मामले -~8में बहुत चालाक है। :) अच्छा जवाब btw, मुझे से +1! बहुत स्मार्ट इस तरह से बिट्स में सभी जानकारी संग्रहीत, यहां तक ​​कि एक बाइट की बचत Bob
केविन क्रूज़सेन 12

2

पायथन 2: 2.765 (70 बाइट्स बचा, 641 बाइट प्रोग्राम)

मैंने अपना दृष्टिकोण थोड़ा बदल दिया। यह अब अपूर्ण palindromes पर अच्छी तरह से काम करता है। कोई संकुचित स्ट्रिंग्स नहीं हैं जो इनपुट से अधिक लंबा होगा। सही सम-लंबाई वाले पैलिंड्रोम्स हमेशा मूल आकार से 50% तक संकुचित होंगे।

A=lambda x:chr(x).isalpha()
def c(s):
 r=bytearray(s);q=len(r);L=0;R=q-1;v=lambda:R+1<q and r[R+1]<15
 while L<=R:
  while not A(r[L])and L<R:L+=1
  while not A(r[R])and R:
   if v()and r[R]==32:r[R]=16+r.pop(R+1)
   R-=1
  j=r[L];k=r[R]
  if A(j)*A(k):
   if L!=R and j&31==k&31:
    r[L]+=(j!=k)*64;r[R]=1
    if v():r[R]+=r.pop(R+1)
   else:r[L]|=128;r[R]|=128
  L+=1;R-=1
 while r[-1]<16:r.pop()
 return r
def d(s):
 r='';t=[]
 for o in s:
  if 15<o<32:r+=' ';o-=16
  while 0<o<16:r+=chr(t.pop());o-=1
  if o==0:continue
  if 127<o<192:o-=64;t+=[o^32]
  elif o>192:o-=128
  elif A(o):t+=[o]
  r+=chr(o)
 while t:r+=chr(t.pop())
 return r

परिणाम

'tacocat' <==> 'tac\xef'
4/7 (3 bytes saved)
'toohottohoot' <==> 'toohot'
6/12 (6 bytes saved)
'todderasesareddot' <==> 'todderas\xe5'
9/17 (8 bytes saved)
'amanaplanacanalpanama' <==> 'amanaplana\xe3'
11/21 (10 bytes saved)
'wasitacaroracatisaw?' <==> 'wasita\xe3ar\xef\x09?'
12/20 (8 bytes saved)
'Bob' <==> '\x82\xef'
2/3 (1 bytes saved)
'IManAmRegalAGermanAmI' <==> 'I\x8d\xa1n\x81m\x92e\xa7\xa1\xec'
11/21 (10 bytes saved)
'Dogeeseseegod' <==> '\x84ogees\xe5'
7/13 (6 bytes saved)
'A Santa at NASA' <==> 'A S\xa1\xaeta\x12\x14'
9/15 (6 bytes saved)
"Go hang a salami! I'm a lasagna hog." <==> "\x87o hang a salam\xa9!\x11'\x01\x11\x17\x13."
24/36 (12 bytes saved)

और एक बोनस के रूप में, यह मेरे गलत पैलिंड्रोम पर 6 बाइट्स बचाता है जो मैंने पहले किया था।

'wasita\xe3ar\xef\x02\xf2\x06?' <==> 'wasitacaroraratisaw?'
6 bytes saved

व्याख्या

अपघटन एक स्टैक का उपयोग करता है। 32-127 से कोडपॉइंट्स का शाब्दिक इलाज किया जाता है। यदि कोई अक्षर एक अक्षर है, तो एक मान स्टैक पर भी धकेल दिया जाता है। 128-192 मानों का उपयोग केस फ़्लिप किए गए पत्रों के लिए किया जाता है, इसलिए केसफ्लिप पत्र (o^32 क्योंकि ASCII कैसे निर्धारित किया जाता है) स्टैक पर धकेल दिया जाता है और सामान्य अक्षर स्ट्रिंग में जुड़ जाता है। मान 192-255 का उपयोग अक्षरों को स्टैक पर धकेलने के बिना जोड़ने के लिए किया जाता है, इसलिए इसका उपयोग तब किया जाता है जब अक्षर मेल नहीं खाते हैं और बीच के अक्षर के लिए विषम-लंबाई वाले पलिंड्रोम में होते हैं। कोडपॉइंट्स 1-15 से संकेत मिलता है कि स्टैक को उस समय की संख्या में पॉप किया जाना चाहिए। कोडपॉइंट्स 17-31 समान हैं, लेकिन वे स्टैक से पॉपिंग करने से पहले पहले एक स्पेस प्रिंट करते हैं। एक इनपुट के अंत में एक खाली "अनुदेश तक एक निहित" पॉप भी है।

कम्प्रेसर 1-31 से मेल खाते अक्षरों में दोनों सिरों और सिलवटों से काम करता है। यह गैर-पत्रों पर छोड़ देता है। जब पत्र मेल खाते हैं, लेकिन मामला नहीं होता है, तो यह बाएं अक्षर में 64 जोड़ देता है और सही अक्षर बढ़ाता है। यह इस पर अंतरिक्ष को बचाने के लिए अनुमति देता है IManAmRegalAGermanAmI। बीच में या जब पत्र मेल नहीं खाते हैं, तो यह दोनों ओर 128 से परिक्रमा करता है। मैं वहाँ नहीं जोड़ सकता क्योंकि मुझे विशेष मामले से बचने की ज़रूरत है जहाँleft == right । जब दाईं ओर पड़ोसी पॉप मार्करों को तह करते हैं, तो मुझे यह जांचना होगा कि पड़ोसी एक कोडपॉइंट 16 में अतिप्रवाह नहीं करेगा क्योंकि मुझे रिक्त स्थान के लिए इसकी आवश्यकता है। (यह वास्तव में परीक्षण के किसी भी मामले के लिए एक मुद्दा नहीं है)

संपादित 1 : कोई और अधिक अनगढ़ संस्करण नहीं है।


1

पायथन 3, 1.833 (25 बाइट बचाई गई, 186 बाइट प्रोग्राम)

बस सरल 0-ऑर्डर समान-संभाव्यता एन्ट्रापी कोडिंग। कोई तालमेल-विशिष्ट अनुकूलन नहीं।

def C(s):
    u=0
    for c in s:u=u*96+ord(c)-31
    return u.to_bytes((u.bit_length()+7)//8,'big')
def D(a):
    u,s=int.from_bytes(a,'big'),''
    while u:s,u=s+chr((u%96)+31),u//96
    return s[::-1]

0

जावा 8, स्कोर: 1.355 (20 बाइट्स बचा / 218 (107 + 111) बाइट्स)

संपीड़ित फ़ंक्शन (जिसमें तीन अप्राप्य ASCII वर्ण हैं):

s->{int l=s.length();return s.contains(new StringBuffer(s).reverse())?s.substring(l/2)+(l%2<1?"":""):s;}

डीकंप्रेस फ़ंक्शन (जिसमें दो अप्राप्य ASCII वर्ण हैं):

s->{return s.contains("")?new StringBuffer((s=s.replaceAll("","")).substring(s.length()&1^1)).reverse()+s:s;}

स्पष्टीकरण:

इसे ऑनलाइन आज़माएं।

केवल सही palindromes संपीड़ित करता है।

s->{                      // Method with String as both parameter and return-type
  int l=s.length();       //  Get the length of the input
  return s.contains(new StringBuffer(s).reverse())?
                          //  If the input is a palindrome:
    s.substring(l/2)      //   Only return the second halve of the String
    +(l%2<1?"":"")        //   + either one (if even) or two (if odd) unprintables 
   :                      //  Else:
    s;}                   //   Simply return the input again

s->{                      // Method with String as both parameter and return-type
  return s.contains("")?  //  If the input contains an unprintable:
    new StringBuffer((s=s.replaceAll("",""))
                          //   Remove the unprintables
                     .substring(s.length()&1^1))
                          //   And take either the full string (if even),
                          //   or minus the first character (if odd)
    .reverse()            //    And reverse that part
    +s                    //   And append the rest of the input (minus the unprintables)
   :                      //  Else:
    s;}                   //   Simply return the input again
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.