Desafío
Escriba un programa que comprima y descomprima el texto ASCII sin pérdidas. Debe estar especializado para trabajar bien con palíndromos, incluidos los palíndromos que no distinguen entre mayúsculas y minúsculas y signos de puntuación. La mejor compresión con la fuente más pequeña gana.
Puntuación
total_bytes_saved / sqrt(program_size)
- Mayor puntaje gana
total_bytes_saved
es cuántos bytes son más pequeñas las cadenas comprimidas que los originales, total en los casos de prueba a continuación. program_size
es el tamaño en bytes del código fuente de los programas de compresión y descompresión. El código compartido entre los dos solo debe contarse una vez.
Por ejemplo, si hay 10 casos de prueba y un programa de 100 bytes guardó 5 bytes en 7 casos de prueba, 10 cada uno en 2 de ellos, pero el último caso de prueba fue 2 bytes más largo, la solución obtendría 5,3. ( (7 * 5 + 10 * 2 - 2) / sqrt(100) = 5.3
)
Casos de prueba
tacocat
toohottohoot
todderasesareddot
amanaplanacanalpanama
wasitacaroracatisaw?
Bob
IManAmRegalAGermanAmI
DogeeseseeGod
A Santa at NASA
Go hang a salami! I'm a lasagna hog.
Reglas
- Se aplican lagunas estándar.
- La compresión debe funcionar en todas las cadenas de texto ASCII imprimibles (bytes 32-126, inclusive), no solo palíndromos. Sin embargo, en realidad no tiene que ahorrar espacio para ninguna entrada.
- La salida puede ser cualquier secuencia de bytes o caracteres, independientemente de su implementación o representación interna (las cadenas, las listas y las matrices son juegos justos, por ejemplo). Si codifica para UTF-8, cuente bytes, no caracteres. Las cadenas anchas (por ejemplo, UTF-16 o UTF-32) no están permitidas a menos que los únicos puntos de código posiblemente utilizados estén entre 0 y 255.
- La compresión / descompresión incorporada no está permitida.
En aras de nuestro propio disfrute, publique las cadenas comprimidas con su código fuente.
ACTUALIZACIÓN 1: La puntuación cambió de total_bytes_saved / program_size
a total_bytes_saved / sqrt(program_size)
para dar más peso a una mejor compresión y menos peso al golf agresivo. Ajuste sus puntajes en consecuencia.
ACTUALIZACIÓN 2: arreglado wasitacaroraratisaw?
para serwasitacaroracatisaw?
fuente
wasitacaroraratisaw?
es un contraejemplo para eso[32-126]
?1000 *
parte sea realmente necesaria, y no, no creo que haga que el puntaje se sienta más "satisfactorio";)Respuestas:
JavaScript (ES6), 3.143 (81 bytes guardados, programa de 664 bytes)
Ahora que estoy bastante satisfecho con este programa (y el sistema de puntuación), escribiré un poco de explicación.
La idea básica es comprimir la entrada en una cadena de bits, luego comprimir cada conjunto de 8 bits en un byte. Para fines de explicación, simplemente manipularé la cadena de bits.
La cadena de bits se puede separar en varias secciones:
El encabezado es un mapeo muy simple:
Los datos de las cartas también son bastante simples. Primero, todas las no letras se extraen de la cadena y todas las letras se convierten a mayúsculas. Si la cuerda resultante es un palíndromo, la mitad invertida se despoja. Luego se aplica esta asignación:
Esta sección se termina con
111
. Después de eso vienen los datos de estilo, que almacenan datos en mayúsculas / minúsculas y no letras. Esto funciona así:Entonces, siguiendo el ejemplo que se muestra arriba, tenemos
Cuando se alcanza el final de la cadena de bits, todos los caracteres restantes de los datos de la letra se agregan al resultado. Esto nos ahorra tener que hacer un último
000...001
y nos permite truncar estos bits de la cadena.Pasando por los casos de prueba:
fuente
Bob
.Bob
realmente encajó en su lugar: 1 bit para el encabezado, 10 + 3 bits para las dos letras y 2 bits para la letra mayúscula. No podría hacerlo más corto si lo intentara con todas mis-0+9
+9
concat a la cadena, mientras que-~8
lo haría+9
aritméticamente (ya-
que no hace nada por las cadenas, por lo que lo interpreta como un número). En ese caso-~8
es bastante inteligente. :) Bonita respuesta por cierto, +1 de mi parte! Muy inteligente almacenando toda la información en bits como ese, incluso guardando un byteBob
.Python 2: 2.765 (70 bytes guardados, programa de 641 bytes)
Cambié mi enfoque un poco. Ahora funciona bien en palíndromos imperfectos. No hay cadenas comprimidas que sean más largas que la entrada. Los palíndromos perfectos de longitud uniforme siempre se comprimirán al 50% del tamaño original.
Resultados
Y como beneficio adicional, ahorra 6 bytes en mi palíndromo incorrecto que tenía antes.
Explicación
La descompresión usa una pila. Los puntos de código del 32 al 127 se tratan literalmente. Si un carácter es una letra, también se inserta un valor en la pila. Los valores 128-192 se usan para letras mayúsculas y minúsculas, por lo que la letra mayúscula (
o^32
debido a cómo se presenta ASCII) se inserta en la pila y la letra normal se agrega a la cadena. Los valores 192-255 se usan para agregar letras sin empujar a la pila, por lo que esto se usa cuando las letras no coinciden y para la letra del medio en palíndromos de longitud impar. Los puntos de código 1-15 indican que la pila debería aparecer esa cantidad de veces. Los puntos de código 17-31 son similares, pero imprimen un espacio primero antes de aparecer en la pila. También hay una instrucción implícita de "pop hasta vacío" al final de una entrada.El compresor funciona desde ambos extremos y se pliega en letras coincidentes como valores 1-31. Se salta sobre las no letras. Cuando las letras coinciden pero el caso no, agrega 64 a la letra izquierda e incrementa la letra derecha. Esto le permite ahorrar espacio
IManAmRegalAGermanAmI
. En el medio o cuando las letras no coinciden, son 128 a ambos lados. No puedo agregar allí porque necesito evitar el caso especial dondeleft == right
. Al plegar los marcadores pop vecinos en el lado derecho, tengo que verificar que el vecino no se desborde en el punto de código 16 porque lo necesito para los espacios. (Esto no es realmente un problema para ninguna de las cadenas de casos de prueba)EDITAR 1 : No más versiones sin golf.
fuente
Python3, 1.833 (25 bytes guardados, programa de 186 bytes)
Simplemente codificación de entropía de igual probabilidad de orden 0. Sin optimizaciones específicas de palíndromo.
fuente
Java 8, puntuación: 1.355 (20 bytes guardados / 218 (107 + 111) bytes)
Función de compresión (contiene tres caracteres ASCII no imprimibles):
Función de descompresión (contiene dos caracteres ASCII no imprimibles):
Explicación:
Pruébalo en línea.
Solo comprime palíndromos perfectos.
fuente