Kim Kolmogorov karmaşıklığı kazanan olmak ister?


22

Bugün sizin göreviniz bir metin kompresörü icat etmektir.

Görev

İki fonksiyon yazacaksınız:

  • Paketleyici ASCII karakter (U 007F için U + 0000) bir dizi kabul eder ve mümkün olan en az karakter içeren, bir Unicode dizgisini (U 10FFFF değerinden U + 0000) çıkaran bir fonksiyonudur.

  • Paket açıcı kodlanmış Unicode dizesi kabul eder ve tam olarak orijinal ASCII dizge çıktılar bir fonksiyondur.

Giriş

Tek yetkili giriş ASCII dizesidir (paketleyici için) ve paketlenmiş Unicode dizisidir (paketinden çıkarmak için). Kullanıcı girişi yok, internet bağlantısı yok, dosya sistemi kullanılamıyor.

İşlevleriniz bu ingilizce kelime listesine erişebilir . Bu listeyi yerel bir txt dosyası olarak kullanabilir veya içeriğini kaynak kodunuzda bir dize veya bir dize dizisi olarak kopyalayabilirsiniz .

İşlevlerinizde aşağıdaki snippet'leri zor kodlayamazsınız.

Çıktı

Her iki işlev için de tek yetkili çıktı bir karakter dizisidir.

Paketleyicinin çıktısı, paketleyicinin girdisiyle tamamen aynı karakterleri içermelidir.

Girişleriniz ve çıkışlarınız, tüm Unicode'u (UTF-8/16/32, GB18030, ...) destekleyen herhangi bir karakter kodlamasını kullanabilir, çünkü puanınız yalnızca çıktıdaki Unicode karakter sayısına bağlı olacaktır. Lütfen, hangi kodlamayı kullandığınıza emin olun.

Çıktınızdaki Unicode karakterlerin sayısını saymak için bu aracı kullanabilirsiniz: http://mothereff.in/byte-counter

puanlama

Girişiniz (bu foruma aldığım) takip eden 10 metin parçasını paketleyip açabilmelidir.

Puanınız, 10 paketlenmiş dizginizin boyutlarının (Unicode karakterlerinde) + iki işlevinizin boyutudur (Unicode karakterlerinde de)

Kullanırsanız, sözlük boyutunu saymayın.

Lütfen girişlerinize her snippet'in "puanını" ve paketlenmiş sürümlerini ekleyin.

En düşük puan kazanır.

Veri

İşte puanınızı hesaplamak için kodlanacak pasajlar:

1: Rick Roll şarkı sözleri (1870b): Biz golf kodlayacak yabancı değiliz, kuralları biliyorsunuz, ve ben de

Biz sevecek yabancı değiliz
Kuralları biliyorsun, ben de
Tam bir bağlılık düşündüğüm şey
Bunu başka bir erkekten almazsın
Sadece sana nasıl hissettiğimi söylemek istiyorum
Anlamanı sağlamalıyım

Senden asla vazgeçmeyeceğim
Seni asla hayal kırıklığına uğratmayacağım
Asla koşup seni terk etmeyeceğim
Seni asla ağlatmayacağım
Asla elveda demeyeceğim
Asla yalan söylemeyecek ve sana zarar vermeyeceğim

Birbirimizi uzun zamandır tanıyoruz.
Kalbin ağrıyor ama
Söylemek için çok utangaçsın
İçimizde ikimiz de neler olduğunu biliyoruz.
Oyunu biliyoruz ve oynayacağız
Ve bana nasıl hissettiğimi sorarsan
Sakın bana görmeyecek kadar kör olduğunu söyleme

Senden asla vazgeçmeyeceğim
Seni asla hayal kırıklığına uğratmayacağım
Asla koşup seni terk etmeyeceğim
Seni asla ağlatmayacağım
Asla elveda demeyeceğim
Asla yalan söylemeyecek ve sana zarar vermeyeceğim

Senden asla vazgeçmeyeceğim
Seni asla hayal kırıklığına uğratmayacağım
Asla koşup seni terk etmeyeceğim
Seni asla ağlatmayacağım
Asla elveda demeyeceğim
Asla yalan söylemeyecek ve sana zarar vermeyeceğim

(Ooh, pes et)
(Ooh, pes et)
(Oh)
Asla vermeyeceğim, asla vermeyeceğim
(Pes)
(Oh)
Asla vermeyeceğim, asla vermeyeceğim
(Pes)

Birbirimizi uzun zamandır tanıyoruz.
Kalbin ağrıyor ama
Söylemek için çok utangaçsın
İçimizde ikimiz de neler olduğunu biliyoruz.
Oyunu biliyoruz ve oynayacağız

Sadece sana nasıl hissettiğimi söylemek istiyorum
Anlamanı sağlamalıyım

Senden asla vazgeçmeyeceğim
Seni asla hayal kırıklığına uğratmayacağım
Asla koşup seni terk etmeyeceğim
Seni asla ağlatmayacağım
Asla elveda demeyeceğim
Asla yalan söylemeyecek ve sana zarar vermeyeceğim

Senden asla vazgeçmeyeceğim
Seni asla hayal kırıklığına uğratmayacağım
Asla koşup seni terk etmeyeceğim
Seni asla ağlatmayacağım
Asla elveda demeyeceğim
Asla yalan söylemeyecek ve sana zarar vermeyeceğim

Senden asla vazgeçmeyeceğim
Seni asla hayal kırıklığına uğratmayacağım
Asla koşup seni terk etmeyeceğim
Seni asla ağlatmayacağım
Asla elveda demeyeceğim
Asla yalan söylemeyecek ve sana zarar vermeyeceğim

2: Golfçü (412b): Golf ASCII-sanat

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

3: elmas (233b): Bu el yazısını yazdır

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

4: alfabeyi dört kez (107b): alfabeyi dört kez yazdırın

abcdefghijklmnopqrstuvwxyz
qwertyuiopasdfghjklzxcvbnm
pyfgcrlaoeuidhtnsqjkxbmwvz
zyxwvutsrqponmlkjihgfedcba

5: Old McDonald's şarkı sözleri (203b): Old MacDonald işlevi

Yaşlı MacDonald'ın bir çiftliği vardı, EIEIO.
Ve o çiftlikte bir ineği vardı, EIEIO,
Burada bir moo moo ve bir moo moo var.
Burada bir moo, bir moo, her yerde bir moo moo,
Yaşlı MacDonald'ın bir çiftliği vardı, EIEIO!

6: Saatin etrafında Rock şarkı sözleri (144b): Saatin etrafında Rock

1, 2, 3, 4, saat rock,
5, 6, 7, 8,
9, 10, 11, 12
Bu gece saatlerce sallanacağız.

7: Merhaba Dünya (296b): ASCII sanatında dünyaya "Merhaba" deyin

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

8: İrlandalı kutsama (210b): Eski bir İrlandalı kutsama

Yol seninle tanışabilsin
Rüzgar her zaman arkanızdan essin
Güneş yüzünüzde parlasın
Yağmurlar tarlalarınızda yumuşak kalır
Ve tekrar buluşana kadar
Tanrı sizi Elinin çukurunda tutabilir

9: Yaşlı bir bayan vardı şarkı sözleri (1208b): Yaşlı bir bayan vardı

Sinek yutan yaşlı bir kadın vardı.  
Neden bu sineği yuttuğunu bilmiyorum.  
Belki de ölür.

Bir örümceği yutan yaşlı bir kadın vardı.  
Bu kıvrılmış ve sallandı ve içinde çalkalandı.  
Sinekleri yakalamak için örümceği yuttu,  
Neden bu sineği yuttuğunu bilmiyorum.  
Belki de ölür.

Kuş yutan yaşlı bir kadın vardı.  
Bir kuşu yutmak ne kadar saçma.  
Örümceği yakalamak için kuşu yuttu,  
Sinekleri yakalamak için örümceği yuttu,  
Neden bu sineği yuttuğunu bilmiyorum.  
Belki de ölür.

Bir kediyi yutan yaşlı bir kadın vardı.  
Bunu bir kediyi yutacağınızı düşünün.  
Kuşu yakalamak için kediyi yuttu.  
Örümceği yakalamak için kuşu yuttu,  
Sinekleri yakalamak için örümceği yuttu,  
Neden bu sineği yuttuğunu bilmiyorum.  
Belki de ölür.

Bir köpeği yutan yaşlı bir kadın vardı.  
Bir köpek yutmak için ne domuz.  
Kediyi yakalamak için köpeği yuttu.  
Kuşu yakalamak için kediyi yuttu.  
Örümceği yakalamak için kuşu yuttu,  
Sinekleri yakalamak için örümceği yuttu,  
Neden bu sineği yuttuğunu bilmiyorum.  
Belki de ölür.

Atı yutan yaşlı bir kadın vardı.  
Elbette öldü.

10: gettysburg adresi (1452b): Gettysburg adresi ne kadar rastgele

Dört puan ve yedi yıl önce babalarımız, bu kıtada, özgürce algılanan ve tüm erkeklerin eşit yaratılması önerisine adanmış yeni bir ulus ortaya koydu. Şimdi biz büyük bir iç savaşa giriyoruz, o milletin veya bu şekilde tasarlanmış ve çok özel bir ulusun uzun süre dayanıp dayanamayacağını test ediyoruz. Bu savaşın büyük bir savaş alanında karşılandık. Bu alanın bir kısmını adamaya geldik, burada yaşamlarını veren millet için yaşayabilecekleri için son bir dinlenme yeri olarak. Bunu yapmamız gereken tamamen uygun ve doğru. Ancak, daha geniş anlamda, adanamayız, umursamayız, bu zemini yarıya alamayız. Burada mücadele eden, yaşayan ve ölü olan cesur insanlar, ekleme veya düşürme gücümüzün çok üstünde, onu kutladılar. Dünya çok az not tutacak ve ne dediğimizi hatırlayamayacak. ama burada ne yaptıklarını asla unutamaz. Bizim için yaşam, daha doğrusu, burada savaşmış oldukları bitmemiş işlere, bu zamana kadar çok ileri düzeyde olanlara adamaktır. Bizden önce kalan büyük göreve adanmış olmak bizim için daha doğrudur - bu onurlu ölülerden, son adanmışlık ölçüsünü verdikleri bu nedene olan bağlılığımızı arttırdık - bu ölülerin, boşuna vefat etti - bu ulus, Tanrı'nın altında yeni bir özgürlük doğuracak ve halkın hükümeti, insanlar tarafından, insanlar için dünyadan yok olmayacak.

Toplam (sıkıştırılmamış): 6135 karakter / bayt.

İyi eğlenceler!


7
Bu bir dili icat etmek için bir meydan okuma değil, bir şeyi sıkıştırmak için bir meydan okumadır.
Justin,

2
Derleyiciye / uygulayıcıya (kompresör / dekompresör) boyutunun skorla dahil edilmemesinin, bu mücadeleyi biraz açık uçlu hale getirdiğini düşünüyorum. Bir noktada, sözlük ve sabit kodlama arasındaki çizgi çok ince olacak.
Dennis,

2
Kahretsin, ve ben burada çoktan private static final String RICK_ROLL_RETURN = "We're no strangers to love...
Graph Theory

1
Dennis'in gözlemine hitap ettiğini sanmıyorum.
Peter Taylor

1
@xem Yazının, bilgileri #Task, #Input, #Output, #Scoring gibi bölümler halinde düzenleyerek geliştirilebileceğini düşünüyorum. Ayrıca kompresör ve dekompresörün kaynak kodunun boyutunun da skora dahil edilmesi gerektiğini düşünüyorum. Bu hiçbir şeye zarar vermez, ancak Dennis'in işaret ettiği sorunu çözer.
Rainbolt

Yanıtlar:


6

Haskell - 5322 puan

Kod baytları: 686

Orijinal boyut : 6147 = 1871+415+234+108+204+145+297+211+1209+1453

Kodlanmış boyutu: 4636 = 1396+233+163+92+153+115+197+164+979+1144

Gol : 686+ 4636

Karakter sayısı sıkıştırma: ~25%

kod

Optimizasyonlar bir yana, bu değerleri unicode karakterleri arasında 0ve 7fasal çarpanları olarak saklar .

Kodlanan çıktının bayt sayısını düşürmez, yalnızca unicode karakter sayısını azaltır. Örneğin, test # 4 108karakterleri ve kodlanmış çıktıları içerir 92. Bununla birlikte, kendi boyutlarına 108ve 364bayt.

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]

Nasıl çalışır

  • Kodlama

    1. Her karakter sayısal eşdeğerine dönüştürülür, bu numarayı arayabilir n.
    2. ndaha sonra ana faktörlerin bir listesine dönüştürülür ps.
      • Elverişli bir şekilde, 0 ila 127 arasındaki sayılar hariç, 32 ortak ana faktöre sahiptir 1. Bu, faktörler, 5 bit kadar küçük bir indeks olarak saklanabilecekleri anlamına gelir.
      • 1 özel bir durumdur ve boş bir liste ile gösterilir.
    3. İle pskodlama şimdi başlayabilirsiniz.
      1. Her bir sayı, ps32 benzersiz faktörler listesinde indeksine dönüştürülür (Yukarıdaki kodda bu liste olarak tanımlanmıştır a).
      2. (Bu noktada, asal faktörlerin indekslerinin bir listesi ile uğraştığımızı unutmayın) Bir sonraki adıma geçmek için psdüzleştirilmesi gerekir. Verilerin bütünlüğünü korumak için, her liste iki bölümden oluşan başka bir listeye dönüştürülür
        1. İlk eleman uzunluğunu saklar ve aynı faktörden oluşuyorsa.
          • Liste başına en fazla 6 ana faktör vardır, bu bilgi en sağdaki 3 bitte saklanır. Beşinci bit, listenin tek bir faktörden oluşup oluşmadığını göstermek için bayrak olarak kullanılır.
        2. Kalan unsurlar, listede ikiden az farklı faktör varsa, endekslerin kendileri veya tek bir endekslerdir.
      3. Bu listeler daha sonra düzleştirilmiş tek bir listede birleştirilir fs.
    4. Öğeleri fsdaha sonra bit kaydırma kullanılarak unicode karakterlere paketlenebilir.
  • Decoding

    • Kodlama adımlarını tersten yapın.
    • Buna nasıl 1uyandığını merak ediyorsan , sana bunu hatırlatmak isterim product [] == 1.

Testler

Test etmek için bu arayüzü kullanmak ağrılı olacaktır, bu yüzden aşağıdaki sonuçları vermek için bu fonksiyonu kullandım.

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

Numune

gTest # 4 için kodlama işlevinin çıktısı şudur
"\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"
ya da anlamsız davranıyorsanız, bu
𘑥򎑡𡁢𑒁豱󐰢𼝤􈓃𐲂숼𨐢𐨽𘑥𐦅􈐤򏡡𒁃񈰡񐱂𰠱𑃥􈑃򑑁򔓂踾𑃱󐰢񀰡񔢣𐣃𐲂𓂡􈒑󈡩𠐣𘰢𼝤􈓂숼𨐢𐡁򑐡衣𐢢쑡𡁡𙘽򉡁𙐡􉉅𘑇򎱢𑑡𒂡衂򎑂񤝃𐣃𐲄􈱤􈓃􊡡𙑃񌟂숼𨐡𐱡𡈽𑃢쑁򔓂豁򔢥􈑃𑃢쑢𑡡ꡃ񈰢񄟅􈐤𐦃貱󩐡𐡑󠠰𘡤𠐡𴝣裱󑀡𘱢𑑡𡈹

Ek notlar

  • Http://mothereff.in/byte-counter kullanarak , dizin listeleri ve edTesttestlerin boyutu tutarlı olmakla birlikte, yine de soruda belirtilen boyuttan farklıdır.
  • Deney 10. Uzun tire bir çift (içeriyor ı ile değiştirilmesi olduğunu) -dışarıdan ait olduğundan 0- 7faralık.
  • Düzleştirme yapılırken kalan dördüncü bit kullanılarak daha fazla sıkıştırma elde edilebilir, örneğin, 00temel durum, 01hepsini 10tekrarla, 11son hariç tekrarla , son iki dışında tekrarla.
  • Test dosyaları ve kodların hepsi burada bulunabilir https://github.com/gxtaillon/codegolf/tree/master/Kolmogorov

Merhaba, bu cevap için teşekkürler! :) Ben dönüştürmek zaman ikili neler olduğunu anlamadı abcdefghijklm...için 𘑥򎑡𡁢𑒁豱󐰢𼝤...bunu açıklamak biraz daha misin? Ayrıca, char sayımlarını düzelttim ve sorudaki # 10'daki em çizgilerini de dönüştürdüm. Karakter sayım yine de sizinkinden farklı. Neden bilmiyorum, ben mothereff.in aracını kullandım.
xem

@xem Karmaşık detaylar ortaya çıktı.
gxtaillon

Aklım (mecazi olarak) kelimenin tam anlamıyla 0 ve 2-127 sayılarının 5 bit üzerinde kodlanabileceği fikrine çarpıyor. Bunu kendin mi buldun yoksa bilinen bir şey mi var? Bonus sorusu: Yalnızca yazdırılabilir ascii karakterlerini, yani 95 farklı karakteri saklamak için kaç bit gerekir?
xem

@xem Sayılar 5 bit üzerinde kodlanmaz, her bir faktör faktördür. Sadece 5 bitlik 7 bit kodlama yöntemi bulmuş olsaydım çok mutlu olurdum.
gxtaillon

1
Belirttiğiniz aralıkta sayı başına en fazla 6 faktör olduğundan, uzunluk 5 bitlik bir "blok" un 3'ünü kullanır. Sonra dizinler 5 bit üzerinde kodlanır, evet. Bu uygulamada, uzunluk bloğundaki kullanılmayan 2 bitten biri ek sıkıştırma elde etmek için kullanılır.
gxtaillon

4

C ++ (C ++ 11), 2741 puan

Bu cevap, sıkıştırılmış metnin kodlaması olarak UTF-32'yi kullanır.

#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();}

Char sayar ve puanlama

Kod: 593 karakter (izleyen satırsonu soyulur)

Sıkıştırılmış metinler (unicode karakterler) : 654 + 145 + 82 + 38 + 51 + 104 + 73 + 423 + 506 = 2148 ( wc -mbayt yerine unicode karakter sayısıyla sayılır) , bayt sayısı @ gxtaillon'un cevabında olduğu gibi orijinallerden daha yüksek, sayıldığı gibi toplamda 8413 bayt wc -c.

Sıkıştırma oranı (ASCII'den unicode'a) :% 35.01 (sorudan gelen 6135 bayt kullanılarak (aynı wc -c))

Dikkat:

Birçok kabuk bu programın ürettiği unicode karakterleri kullanamaz. Bu nedenle, dekompresyon, kabuğun bir karakterle başa çıkamadığı durumlarda metnin bir yerden kesilmesine yol açabilir, çünkü girdi stdinkabuktan alınır .

Derleme

Derlemesi gereken clang++ve derlemelidir g++ -std=c++11, ancak operatör önceliği ile ilgili bazı uyarılar gösterecektir, çünkü böyle bir ifade beklendiği gibi b<<20-n&0xFFFFFdeğil , olduğu gibi ele alınacaktır .((b << 20) - n) & 0xFFFFF(b << (20 - n)) & 0xFFFFF

kullanım

  • Programı çalıştırılabilir bir dosyada derleyin, örn ./compress.
  • ./compress cSıkıştırmak veya ./compress daçmak için programı çalıştırın . (Seçeneği dışarıda bırakmak, bir SEGFAULT verir (hata kontrolü çok pahalı ...) ve diğer seçenekler ( Dyerine kullanmak gibi d) beklenmedik sonuçlar verebilir
  • Giriş okunur stdinve çıkış yazılırstdout

Nasıl çalışır

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();
}

açıklama

Tüm Unicode karakterleri gibi U+0000hiç U+10FFFFizin verilir, biz Unicode Char başına 20 bit kullanabilirsiniz: U+FFFFF20 bit kullanır ve hala izin verilen aralığın dahildir. Bu nedenle, birden fazla ASCII karakterini tek bir unicode karakterinde saklamak için tüm bireysel ASCII karakter bitlerini unicode karakterlerine sıkıştırmaya çalışıyoruz. Bununla birlikte, son unicode karakterinde kullanılan bit sayısını da kaydetmemiz gerekir, çünkü kullanılmayan çöp bitleri aksi halde uygun sıkıştırılmış ASCII karakterleri olarak yorumlanabilir. Son unicode karakterinde kullanılan maksimum bit sayısı 20 olduğundan, bunun için sıkıştırılmış verilerin başına yerleştirilen 5 bit gerekir.

Örnek çıktı

Bu, örneğin 4 numaralı çıktıdır (tarafından verilen şekilde 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>

( karakter kodları olarak 쏏𦛏verin <U+C3CF><U+266CF>, ancak bunu yanlış almış olabilirim)


2

Python 3, 289 + 818 = 1107 puan

Sadece hafifçe golf oynadım.

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

Toplam kod boyutu 289 bayttır ve verilen 6135 baytı 818 Unicode karakter olarak kodlar - toplam çıktı bayt sayısı, orijinal girdilerden önemli ölçüde daha küçük olan 3201 bayttır.

Zlib kullanarak kodlar, daha sonra ikincil olarak unicode kodlamasını kullanarak kodlar. Suretlerden (Python'un gerçekten nefret ettiği) kaçınmak için biraz fazla mantık gerekiyordu.

less(37 Unicode karakter) tarafından görüldüğü gibi # 4'ten örnek çıktı :

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>

Test için sürücü programı:

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)

Çıkış baytı sayısı:

 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
Bu biraz hile yapan bir sıkıştırma kütüphanesi kullanıyor olmuyor mu?
Beta Decay

@BetaDecay: Bu soruyu kısıtlamıyor, bu yüzden adil bir oyun olduğunu düşündüm.
nneonneo

Ayrıca, bir sıkıştırıcı eklemeniz gerekir.
Beta Çürüğü

@ BetaDecay: ppaketleyici, paketleyici u.
nneonneo

1

Python 2 - 1141 puan

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)

Kod boyutu 281bayttır ve 6135baytları 860unicode karakterlere kodlar .

Nasıl çalışır:

Kodlamak için:

  1. Kodlanacak dizeyi sıkıştırın.
  2. Sıkıştırılmış dizeyi temel 256 sayı olarak yorumlayın.
  3. Sayıyı ikiliye dönüştürün.
  4. İkiliyi 19bit gruplarına ayırın, 1her birinin başına bir bit ekleyin ve ardından Unicode karakterlerine dönüştürün.

Kod çözme tersidir.

Bazı python sürümlerinin yalnızca unicode karakterleri işleyebileceğini 0xFFFFve bu nedenle bu kodun a yükseleceğini unutmayın ValueError.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.