Desafio
Escreva um programa que comprima e descompacte o texto ASCII sem perdas. Deve ser especializado para funcionar bem com palíndromos, incluindo palíndromos que não diferenciam maiúsculas de minúsculas e que não pontuam pontuação. A melhor compactação com a menor fonte ganha.
Pontuação
total_bytes_saved / sqrt(program_size)
- Maior pontuação ganha
total_bytes_saved
é quantos bytes menores as seqüências compactadas são do que os originais, total nos casos de teste abaixo. program_size
é o tamanho em bytes do código-fonte dos programas de compactação e descompactação. O código compartilhado entre os dois precisa ser contado apenas uma vez.
Por exemplo, se houver 10 casos de teste e um programa de 100 bytes salvou 5 bytes em 7 casos de teste, 10 cada em 2 deles, mas o último caso de teste tiver 2 bytes mais, a solução terá 5,3. ( (7 * 5 + 10 * 2 - 2) / sqrt(100) = 5.3
)
Casos de teste
tacocat
toohottohoot
todderasesareddot
amanaplanacanalpanama
wasitacaroracatisaw?
Bob
IManAmRegalAGermanAmI
DogeeseseeGod
A Santa at NASA
Go hang a salami! I'm a lasagna hog.
Regras
- Aplicam-se brechas padrão.
- A compactação deve funcionar em todas as seqüências de texto imprimíveis ASCII (bytes 32-126, inclusive), não apenas nos palíndromos. Na verdade, ele não precisa economizar espaço para nenhuma entrada.
- A saída pode ser qualquer sequência de bytes ou caracteres, independentemente de sua implementação ou representação interna (seqüências de caracteres, listas e matrizes são jogos justos, por exemplo). Se estiver codificando para UTF-8, conte bytes, não caracteres. Cadeias de caracteres largas (por exemplo, UTF-16 ou UTF-32) não são permitidas, a menos que os únicos pontos de código possivelmente usados estejam entre 0 e 255.
- Os componentes de compactação / descompactação não são permitidos.
Para nosso próprio prazer, publique as strings compactadas com seu código-fonte.
ATUALIZAÇÃO 1: A pontuação mudou de total_bytes_saved / program_size
para total_bytes_saved / sqrt(program_size)
para dar mais peso à melhor compressão e menos peso ao golfe agressivo. Ajuste sua pontuação de acordo.
ATUALIZAÇÃO 2: corrigida wasitacaroraratisaw?
para serwasitacaroracatisaw?
fonte
wasitacaroraratisaw?
é um contraexemplo disso[32-126]
?1000 *
parte é realmente necessária, e não, eu não acho que isso fará com que a pontuação pareça mais "satisfatória";)Respostas:
JavaScript (ES6), 3.143 (81 bytes salvos, programa de 664 bytes)
Agora que estou bastante satisfeito com este programa (e o sistema de pontuação), vou escrever uma explicação.
A idéia básica é compactar a entrada em uma sequência de bits e, em seguida, compactar cada conjunto de 8 bits em um byte. Para fins de explicação, manipularei a string de bits.
A cadeia de bits pode ser separada em várias seções:
O cabeçalho é um mapeamento muito simples:
Os dados das cartas também são bastante simples. Primeiro, todas as não letras são extraídas da sequência e todas as letras são convertidas em maiúsculas. Se a sequência resultante for um palíndromo, a metade invertida será removida. Então esse mapeamento é aplicado:
Esta seção termina com
111
. Depois disso, vêm os dados de estilo, que armazenam dados em maiúsculas / minúsculas e sem letras. Isso funciona assim:Então, seguindo o exemplo mostrado acima, temos
Quando o final da sequência de bits é atingido, todos os caracteres restantes dos dados da letra são anexados ao resultado. Isso nos impede de ter que fazer uma última
000...001
e nos permite truncar esses bits da string.Passando pelos casos de teste:
fonte
Bob
também.Bob
realmente se encaixou - 1 bit para o cabeçalho, 10 + 3 bits para as duas letras e 2 bits para a única letra maiúscula. Não poderia ficar mais curto se eu tentasse o meu melhor ...-0+9
+9
concatenaria com a string, enquanto-~8
faria+9
aritmeticamente (já-
que não faz nada por strings, por isso a interpreta como um número). Nesse caso,-~8
é bastante inteligente. :) Boa resposta btw, +1 de mim! Muito inteligente, armazenando todas as informações em bits assim, economizando até um byteBob
.Python 2: 2.765 (70 bytes salvos, programa de 641 bytes)
Mudei de abordagem um pouco. Agora funciona bem em palíndromos imperfeitos. Não há seqüências de caracteres compactadas que serão mais longas que a entrada. Palíndromos perfeitos de comprimento uniforme sempre comprimirão 50% do tamanho original.
Resultados
E como bônus, ele salva 6 bytes no meu palíndromo incorreto que eu tinha antes.
Explicação
A descompressão usa uma pilha. Os pontos de código de 32 a 127 são tratados literalmente. Se um caractere é uma letra, um valor também é enviado para a pilha. Os valores 128-192 são usados para letras com maiúsculas e minúsculas; portanto, a letra com maiúsculas e minúsculas (
o^32
por causa de como o ASCII é organizado) é empurrada para a pilha e a letra normal é adicionada à sequência. Os valores 192-255 são usados para adicionar letras sem empurrar para a pilha; portanto, isso é usado quando as letras não correspondem e para a letra do meio em palíndromos de comprimento ímpar. Os pontos de código 1 a 15 indicam que a pilha deve ser exibida esse número de vezes. Os pontos de código 17 a 31 são semelhantes, mas primeiro imprimem um espaço antes de sair da pilha. Há também uma instrução implícita "pop até vazia" no final de uma entrada.O compressor trabalha nas extremidades e dobras em letras correspondentes como valores de 1 a 31. Ele pula sobre não letras. Quando as letras correspondem, mas o caso não corresponde, adiciona 64 à letra esquerda e incrementa a letra direita. Isso permite economizar espaço
IManAmRegalAGermanAmI
. No meio ou quando as letras não coincidem, ele representa 128 para os dois lados. Não posso adicionar lá porque preciso evitar o caso especial em queleft == right
. Ao dobrar marcadores pop vizinhos no lado direito, tenho que verificar se o vizinho não transbordará para o codepoint 16, porque preciso disso para espaços. (Na verdade, isso não é um problema para nenhuma das sequências de casos de teste)EDIT 1 : Não há mais versão não destruída.
fonte
Python3, 1.833 (25 bytes salvos, programa de 186 bytes)
Apenas codificação de entropia simples com igual probabilidade de ordem 0. Não há otimizações específicas do palíndromo.
fonte
Java 8, pontuação: 1.355 (20 bytes salvos / 218 (107 + 111) bytes)
Função Compactar (contém três caracteres ASCII não imprimíveis):
Função descomprimir (contém dois caracteres ASCII não imprimíveis):
Explicação:
Experimente online.
Comprime apenas palíndromos perfeitos.
fonte