¿Quién quiere ser un ganador de la complejidad de Kolmogorov?

22

Tu misión hoy es inventar un compresor de texto.

Tarea

Escribirás dos funciones:

  • El empaquetador es una función que acepta una cadena de caracteres ASCII (U + 0000 a U + 007F) y genera una cadena Unicode (U + 0000 a U + 10FFFF), que contiene la menor cantidad de caracteres posible.

  • El desempacador es una función que acepta una cadena Unicode codificada y genera exactamente la cadena ASCII original.

Entrada

La única entrada autorizada es la cadena ASCII (para el empacador) y la cadena Unicode empaquetada (para el desempacador). Sin entrada del usuario, sin conexión a Internet, sin uso del sistema de archivos.

Sus funciones pueden tener acceso a esta lista de palabras en inglés . Puede usar esta lista como un archivo txt local, o copiar su contenido en su código fuente como una cadena o una matriz de cadenas .

No puede codificar los fragmentos a continuación en sus funciones.

Salida

La única salida autorizada para ambas funciones es una cadena.

La salida del desempacador debe contener exactamente los mismos caracteres que la entrada del empacador.

Sus entradas y salidas pueden usar cualquier codificación de caracteres que admita todos los Unicode (UTF-8/16/32, GB18030, ...), ya que su puntaje solo dependerá de la cantidad de caracteres Unicode en la salida. Sin embargo, precisa qué codificación estás usando.

Para contar el número de caracteres Unicode en su salida, puede usar esta herramienta: http://mothereff.in/byte-counter

Tanteo

Su entrada debe poder empaquetar y desempaquetar los siguientes 10 fragmentos de texto (que tomé en este foro).

Su puntaje será la suma de los tamaños de sus 10 cadenas empaquetadas (en caracteres Unicode) + el tamaño de sus dos funciones (también en caracteres Unicode)

No cuente el tamaño del diccionario si lo usa.

Incluya en sus entradas el "puntaje" de cada fragmento y su versión empaquetada.

La puntuación más baja gana.

Datos

Estos son los fragmentos para codificar para calcular su puntaje:

1: Letras de Rick Roll (1870b): No somos ajenos al código de golf, conoces las reglas, y yo también

No somos extraños para amar
Conoces las reglas y yo también
Un compromiso total es lo que estoy pensando
No obtendrías esto de ningún otro chico
Solo quiero decirte cómo me siento
Tengo que hacerte entender

Nunca va a dar
Nunca te voy a decepcionar
Nunca voy a correr y abandonarte
Nunca te haré llorar
Nunca voy a decir adios
Nunca diré una mentira y te lastimaré

Nos conocemos desde hace tanto tiempo
Tu corazón ha estado doliendo pero
Eres demasiado tímido para decirlo
En el interior, ambos sabemos lo que ha estado sucediendo.
Conocemos el juego y lo vamos a jugar.
Y si me preguntas cómo me siento
No me digas que estás demasiado ciego para ver

Nunca va a dar
Nunca te voy a decepcionar
Nunca voy a correr y abandonarte
Nunca te haré llorar
Nunca voy a decir adios
Nunca diré una mentira y te lastimaré

Nunca va a dar
Nunca te voy a decepcionar
Nunca voy a correr y abandonarte
Nunca te haré llorar
Nunca voy a decir adios
Nunca diré una mentira y te lastimaré

(Ooh, te rindo)
(Ooh, te rindo)
(Oh)
Nunca daré, nunca daré
(Te rindo)
(Oh)
Nunca daré, nunca daré
(Te rindo)

Nos conocemos desde hace tanto tiempo
Tu corazón ha estado doliendo pero
Eres demasiado tímido para decirlo
En el interior, ambos sabemos lo que ha estado sucediendo.
Conocemos el juego y lo vamos a jugar.

Solo quiero decirte cómo me siento
Tengo que hacerte entender

Nunca va a dar
Nunca te voy a decepcionar
Nunca voy a correr y abandonarte
Nunca te haré llorar
Nunca voy a decir adios
Nunca diré una mentira y te lastimaré

Nunca va a dar
Nunca te voy a decepcionar
Nunca voy a correr y abandonarte
Nunca te haré llorar
Nunca voy a decir adios
Nunca diré una mentira y te lastimaré

Nunca va a dar
Nunca te voy a decepcionar
Nunca voy a correr y abandonarte
Nunca te haré llorar
Nunca voy a decir adios
Nunca diré una mentira y te lastimaré

2: El golfista (412b): Golf ASCII-art

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

3: el diamante número (233b): imprime este diamante

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

4: el alfabeto cuatro veces (107b): imprime el alfabeto cuatro veces

ABCDEFGHIJKLMNOPQRSTU VWXYZ
qwertyuiopasdfghjklzxcvbnm
pyfgcrlaoeuidhtnsqjkxbmwvz
zyxwvutsrqponmlkjihgfedcba

5: Letras de Old McDonald's (203b): Función de Old MacDonald

El viejo MacDonald tenía una granja, EIEIO,
Y en esa granja tenía una vaca, EIEIO,
Con un mu mu mu aquí y un mu mu mu allá
Aquí un mu, hay un mu, en todas partes un mu,
¡El viejo MacDonald tenía una granja, EIEIO!

6: Letra de Rock around the clock (144b): Rock Around the Clock

1, 2, 3 en punto, 4 en punto de roca,
5, 6, 7 en punto, 8 en punto de roca,
9, 10, 11 en punto, roca a las 12 en punto,
Vamos a rockear todo el día esta noche.

7: Hola Mundo (296b): Di "Hola" al mundo en el arte ASCII

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

8: bendición irlandesa (210b): una antigua bendición irlandesa

Que el camino se levante para conocerte
Puede que el viento esté siempre a tu espalda
Que el sol brille sobre tu rostro
Las lluvias caen suaves sobre tus campos
Y hasta que nos encontremos de nuevo
Que Dios te sostenga en el hueco de su mano

9: Había una vieja dama (1208b): Había una vieja dama

Había una anciana que tragó una mosca.  
No sé por qué se tragó esa mosca  
Quizás ella muera.

Había una anciana que se tragó una araña,  
Eso se retorció, se sacudió y se sacudió dentro de ella.  
Ella se tragó la araña para capturar la mosca,  
No sé por qué se tragó esa mosca  
Quizás ella muera.

Había una anciana que se tragó un pájaro,  
Qué absurdo tragarse un pájaro.  
Se tragó el pájaro para atrapar a la araña,  
Ella se tragó la araña para capturar la mosca,  
No sé por qué se tragó esa mosca  
Quizás ella muera.

Había una anciana que se tragó un gato,  
Imagina que tragar un gato.  
Se tragó al gato para atrapar al pájaro,  
Se tragó el pájaro para atrapar a la araña,  
Ella se tragó la araña para capturar la mosca,  
No sé por qué se tragó esa mosca  
Quizás ella muera.

Había una anciana que se tragó un perro,  
Qué cerdo tragarse un perro.  
Se tragó al perro para atrapar al gato,  
Se tragó al gato para atrapar al pájaro,  
Se tragó el pájaro para atrapar a la araña,  
Ella se tragó la araña para capturar la mosca,  
No sé por qué se tragó esa mosca  
Quizás ella muera.

Había una anciana que se tragó un caballo,  
Ella murió por supuesto.

10: dirección de Gettysburg (1452b): cuán aleatoria es la dirección de Gettysburg

Hace cuatro años y siete años, nuestros padres dieron a luz en este continente una nueva nación, concebida en libertad, y dedicada a la proposición de que todos los hombres son creados iguales. Ahora estamos involucrados en una gran guerra civil, probando si esa nación, o cualquier nación tan concebida y dedicada, puede perdurar por mucho tiempo. Nos encontramos en un gran campo de batalla de esa guerra. Hemos llegado a dedicar una parte de ese campo, como un lugar de descanso final para aquellos que aquí dieron sus vidas para que esa nación pudiera vivir. Es totalmente apropiado y apropiado que hagamos esto. Pero, en un sentido más amplio, no podemos dedicar, no podemos consagrar, no podemos santificar este terreno. Los hombres valientes, vivos y muertos, que lucharon aquí, lo han consagrado, muy por encima de nuestro pobre poder para sumar o restar valor. El mundo notará poco, ni mucho tiempo recordará lo que decimos aquí, pero nunca puede olvidar lo que hicieron aquí. Es para nosotros los vivos, más bien, dedicarnos aquí al trabajo inacabado que los que lucharon aquí han avanzado hasta ahora noblemente. Es más bien para nosotros estar aquí dedicados a la gran tarea que nos queda por delante: que de estos honrados muertos tomemos una mayor devoción a esa causa por la cual dieron la última medida completa de devoción, que aquí resolvamos altamente que estos muertos no han muerto en vano, que esta nación, bajo Dios, tendrá un nuevo nacimiento de libertad, y que el gobierno del pueblo, por el pueblo, por el pueblo, no perecerá de la tierra.

Total (sin comprimir): 6135 caracteres / bytes.

¡Que te diviertas!

xem
fuente
77
No es un desafío inventar un lenguaje, es un desafío comprimir algo.
Justin
2
Creo que no incluir el tamaño del compilador / ejecutor (compresor / descompresor) en la partitura hace que este desafío sea un poco abierto. En algún momento, la línea entre el diccionario y la codificación rígida se volverá muy delgada.
Dennis
2
Maldición, y aquí ya estaba escribiendo private static final String RICK_ROLL_RETURN = "We're no strangers to love...
Graph Theory
1
No creo que hayas abordado la observación de Dennis.
Peter Taylor
1
@xem Creo que la publicación podría mejorarse organizando la información en secciones como #Task, #Input, #Output, #Scoring. También creo que el tamaño del código fuente para el compresor y el descompresor debería incluirse en la partitura. Esto no duele nada, pero resuelve el problema que Dennis señaló.
Rainbolt

Respuestas:

6

Haskell - 5322 puntos

Bytes de código: 686

Tamaño original : 6147 = 1871+415+234+108+204+145+297+211+1209+1453

Tamaño codificado: 4636 = 1396+233+163+92+153+115+197+164+979+1144

Puntuación : 686+ 4636

Compresión de recuento de caracteres: ~25%

Código

Dejando de lado las optimizaciones, esto almacena valores entre 0 y 7fen caracteres unicode como sus factores primos.

No reduce el número de bytes de la salida codificada, solo reduce el número de caracteres unicode. Por ejemplo, la prueba # 4 contiene 108personajes y la salida codificada, 92. Sus respectivos tamaños son, sin embargo 108, y 364bytes.

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]

Cómo funciona

  • Codificación

    1. Cada carácter se convierte a su equivalente numérico, llamemos a este número n .
    2. n luego se convierte en una lista de sus factores primos, ps .
      • Convenientemente sucede que los números del 0 al 127 tienen 32 factores primos comunes, excluyendo 1. Esto significa que ellos, los factores, pueden almacenarse como índices en tan solo 5 bits.
      • 1 es un caso especial y está representado por una lista vacía.
    3. Con ps la codificación ahora puede comenzar.
      1. Cada número de psse convierte en su índice en la lista de 32 factores únicos (en el código anterior, esta lista se identifica comoa ).
      2. (Tenga en cuenta en este punto que estamos tratando con una lista de la lista de índices de factores primos) Para proceder al siguiente paso, ps debe aplanarse. Para preservar la integridad de los datos, cada lista se convierte en otra lista de dos partes
        1. El primer elemento almacena su longitud y si está compuesto por el mismo factor.
          • Hay como máximo 6 factores primos por lista, esta información se almacena en los 3 bits más a la derecha. El quinto bit se usa como indicador para indicar si la lista está compuesta por un solo factor.
        2. Los elementos restantes son los propios índices o un solo índice si hay menos de dos factores diferentes en la lista.
      3. Estas listas se concatenan en una sola lista aplanada, fs.
    4. Los elementos de fsse pueden empaquetar en caracteres unicode utilizando desplazamiento de bits.
  • Descodificación

    • Realice los pasos de codificación a la inversa.
    • Si se pregunta cómo 1encaja en esto, me gustaría recordarle eso product [] == 1.

Pruebas

Usar esta interfaz para probar sería doloroso, así que usé esta función para proporcionar los resultados a continuación.

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

Muestra

La salida de la función de codificación gpara la prueba n. ° 4 es esta
"\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"
o, si eres un experto en galimatías, esto
𘑥򎑡𡁢𑒁豱󐰢𼝤􈓃𐲂숼𨐢𐨽𘑥𐦅􈐤򏡡𒁃񈰡񐱂𰠱𑃥􈑃򑑁򔓂踾𑃱󐰢񀰡񔢣𐣃𐲂𓂡􈒑󈡩𠐣𘰢𼝤􈓂숼𨐢𐡁򑐡衣𐢢쑡𡁡𙘽򉡁𙐡􉉅𘑇򎱢𑑡𒂡衂򎑂񤝃𐣃𐲄􈱤􈓃􊡡𙑃񌟂숼𨐡𐱡𡈽𑃢쑁򔓂豁򔢥􈑃𑃢쑢𑡡ꡃ񈰢񄟅􈐤𐦃貱󩐡𐡑󠠰𘡤𠐡𴝣裱󑀡𘱢𑑡𡈹

Notas adicionales

  • Usando http://mothereff.in/byte-counter , listados de directorios yedTest el tamaño de las pruebas son todos consistentes pero aún difieren del tamaño indicado en la pregunta.
  • Prueba # 10 contiene un par de guiones largos ( ) que reemplacé con -ya que están fuera de la 0- 7fgama.
  • Se podría lograr una mayor compresión usando el cuarto bit restante mientras se aplana, por ejemplo, 00caso base, 01repetir todo, 10repetir excepto el último, 11repetir excepto los últimos dos.
  • Los archivos de prueba y el código están disponibles aquí https://github.com/gxtaillon/codegolf/tree/master/Kolmogorov
gxtaillon
fuente
Hola, gracias por esta respuesta! :) Yo no entendía lo que ocurre en el sistema binario al convertir abcdefghijklm...a 𘑥򎑡𡁢𑒁豱󐰢𼝤..., ¿podría explicar un poco más, por favor? Además, arreglé los recuentos de caracteres y convertí los guiones en # 10, en la pregunta. Sin embargo, mis recuentos de caracteres siguen siendo diferentes a los tuyos. No sé por qué, utilicé la herramienta mothereff.in.
xem
@xem Se han revelado los detalles intrincados.
gxtaillon
Mi mente está (en sentido figurado) literalmente sorprendida por la idea de que los números 0 y 2-127 pueden codificarse en 5 bits. ¿Encontraste esto por ti mismo o era algo conocido? Pregunta adicional: ¿cuántos bits necesita para almacenar solo los caracteres ascii imprimibles, es decir, 95 caracteres diferentes?
xem
@xem Los números no están codificados en 5 bits, cada uno de sus factores sí. Sería muy feliz si hubiera encontrado una forma de codificar 7 bits en solo 5. En cuanto a los caracteres ascii, con este método todavía necesitarían 5 bits cada uno.
gxtaillon
1
Dado que en el rango que especificó hay como máximo 6 factores por número, la longitud utiliza 3 de un "bloque" de 5 bits. Entonces los índices se codifican en 5 bits, sí. En esta implementación, uno de los 2 bits no utilizados en el bloque de longitud se utiliza para obtener una compresión adicional.
gxtaillon
4

C ++ (C ++ 11), 2741 puntos

Esta respuesta usa UTF-32 como codificación para el texto comprimido.

#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 cuenta y anota

Código: 593 caracteres (la nueva línea final se elimina)

Textos comprimidos (caracteres unicode) : 654 + 145 + 82 + 38 + 51 + 104 + 73 + 423 + 506 = 2148 (contados conwc -m el número de caracteres unicode en lugar de bytes, los recuentos de bytes son, como con la respuesta de @ gxtaillon , superior a los originales, 8413 bytes en total, según se cuenta con wc -c).

Relación de compresión (ASCII a Unicode) : 35.01% (utilizando los 6135 bytes de la pregunta (igual quewc -c ))

Tener cuidado:

Muchos shells no pueden manejar los caracteres unicode que produce este programa. Por lo tanto, la descompresión puede hacer que el texto se corte en algún lugar cuando el shell no puede manejar un carácter, ya que la entrada se toma a través destdin desde el shell.

Compilando

Debería compilar con clang++ y g++ -std=c++11, pero mostrará algunas advertencias sobre la precedencia del operador, ya que una expresión como b<<20-n&0xFFFFFno se tratará como ((b << 20) - n) & 0xFFFFF, como cabría esperar, sino como (b << (20 - n)) & 0xFFFFF.

Uso

  • Compile el programa en un ejecutable, por ejemplo ./compress.
  • Ejecute el programa ./compress cpara comprimir o ./compress ddescomprimir. (Cuidado, dejar de lado la opción da un SEGFAULT (la comprobación de errores es muy costosa ...) y otras opciones (como usarD lugar de d) pueden dar resultados inesperados
  • La entrada se lee stdiny la salida se escribe enstdout

Cómo funciona

Sin golf

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

Explicación

Como todos los caracteres Unicode de U+0000a U+10FFFFestán permitidos, podemos usar 20 bits por char Unicode:U+FFFFF usa 20 bits y todavía está incluido en el rango permitido. Por lo tanto, solo intentamos meter todos los bits de caracteres ASCII individuales en los caracteres unicode para almacenar múltiples caracteres ASCII en un carácter unicode. Sin embargo, también necesitamos almacenar el número de bits utilizados en el último carácter unicode, porque los bits basura no utilizados pueden interpretarse como caracteres ASCII comprimidos adecuados. Como el número máximo de bits usados ​​en el último carácter unicode es 20, necesitaremos 5 bits para eso, que se colocan al comienzo de los datos comprimidos.

Salida de ejemplo

Este es el resultado, por ejemplo, # 4 (según lo dado por 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>

( 쏏𦛏dar <U+C3CF><U+266CF>como códigos de caracteres, pero podría haberme equivocado)

hlt
fuente
2

Python 3, 289 + 818 = 1107 puntos

Solo ligeramente golfizado.

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

El tamaño total del código es de 289 bytes y codifica los 6135 bytes dados en 818 caracteres Unicode: el recuento total de bytes de salida es 3201 bytes, significativamente más pequeño que las entradas originales.

Codifica usando zlib, luego secundariamente usando codificación unicode. Se necesitaba algo más de lógica para evitar sustitutos (que Python realmente odia).

Ejemplo de salida del # 4, como se ve en less(37 caracteres Unicode):

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>

Programa de controlador para pruebas:

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)

El byte de salida cuenta:

 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
nneonneo
fuente
1
¿No es el hecho de que esto está usando una biblioteca de compresión haciendo trampa?
Beta Decay
@BetaDecay: No restringe eso en la pregunta, así que pensé que era un juego justo.
nneonneo
Además, debe incluir un descompresor.
Beta Decay
@BetaDecay: pes el empacador, ues el desempacador.
nneonneo
1

Python 2 - 1141 puntos

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)

El tamaño del código es 281 bytes y codifica los 6135bytes en 860caracteres unicode.

Cómo funciona:

Para codificar:

  1. Comprima la cadena que se codificará.
  2. Interprete la cadena comprimida como un número base 256.
  3. Convierte el número a binario.
  4. Divida el binario en grupos de 19bits, agregue un 1bit al comienzo de cada uno de ellos y luego conviértalos en caracteres Unicode.

La decodificación es lo contrario.

Tenga en cuenta que algunas versiones de python solo pueden manejar caracteres unicode hasta y 0xFFFF, por lo tanto, este código generará un ValueError.

pppery
fuente