Comprimir datos RLE para dibujar arte ASCII

11

Esta pregunta se basa en lo que se me ocurrió para responder otra pregunta .

A veces las preguntas aquí piden dibujar un poco de arte ASCII. Una forma sencilla de almacenar los datos para el arte es RLE (codificación de longitud de ejecución) . Entonces:

qqqwwwwweeerrrrrtttyyyy

se convierte en:

3q5w3e5r3t4y

Ahora, para dibujar un gran arte ASCII, es posible que obtenga datos como este (ignorando los nuevos caracteres de línea):

19,20 3(4)11@1$20 11@19,15"4:20 4)19,4:20 11@
   ^^^
   Note that this is "20 whitespaces"

(Character count: 45)

Los caracteres utilizados para el arte ASCII nunca serán letras o números en minúsculas o mayúsculas, solo signos, marcas y símbolos, pero siempre en el conjunto de caracteres ASCII imprimible.

Desea ahorrar algo de espacio en esa cadena, por lo que reemplaza los números con el conjunto de caracteres en mayúscula (siendo 'A' es igual a 1, 'B' es igual a 2 hasta que 'Z' es igual a 26), porque nunca va a obtener más de 26 repeticiones de un personaje. Entonces obtienes:

S,T C(D)K@A$T K@S,O"D:T D)S,D:T K@

(Character count: 34)

Y finalmente observa que algunos grupos de (letra + símbolo) se repiten, por lo que sustituye los grupos que aparecen 3 veces o más en la cadena por el conjunto de caracteres en minúscula, en orden o en la apariencia de la cadena, pero almacenando en un búfer el sustituciones realizadas (en el formato "grupo + sustitución char" para cada sustitución), y dejando el resto de la cadena como está. Entonces los siguientes grupos:

S, (3 times) 
T  (4 times)
K@ (3 times)

se sustituye por 'a', 'b' y 'c', respectivamente, porque nunca habrá más de 26 grupos que se repitan. Entonces finalmente obtienes:

S,aT bK@c
abC(D)cA$bcaO"D:bD)aD:bc

(Character count: 9+24=33)

[El último paso solo guarda 1 byte porque los grupos que realmente guardan caracteres después de ser sustituidos son los que aparecen 4 veces o más.]

El reto

Dada una cadena que contiene los datos RLE para dibujar un arte ASCII (con las restricciones propuestas), escriba el programa / función / método más corto que pueda para comprimirlo como se describe. El algoritmo debe imprimir / devolver dos cadenas: la primera que contiene el diccionario utilizado para la compresión y la segunda es la cadena comprimida resultante. Puede devolver las cadenas como una tupla, una matriz, una lista o lo que sea, en el orden dado.

Tenga en cuenta que si la cadena no se puede comprimir en el paso 2, el algoritmo debe devolver una cadena vacía como primer valor de retorno y el resultado del paso 1 como segundo valor de retorno.

No es necesario incluir el resultado del paso 1 en los valores de salida, solo los incluyo en los ejemplos para fines de aclaración.

Este es el , ¡así que puede ganar la respuesta más corta para cada idioma!

Otro caso de prueba

Input:                   15,15/10$15,15/10"10$10"10$10"10$10"15,15/

Output of step 1:        O,O/J$O,O/J"J$J"J$J"J$J"O,O/

Final algorithm output:  O,aO/bJ$cJ"d
                         abcabdcdcdcdab

---

Input:                   15,15/10$15,15/10"

Output of step 1:        O,O/J$O,O/J"

Final algorithm output:  <empty string>
                         O,O/J$O,O/J"
Charlie
fuente
1
porque nunca vas a obtener más de 26 repeticiones de un personaje Nope. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Okx
@Okx Ese nunca puede ser el caso.
Erik the Outgolfer
@ Ok sí, en el mundo real. Sin embargo, las reglas están hechas para un conjunto restringido de arte ASCII.
Charlie
2
En una implementación real, S,aT bK@cprobablemente se almacenaría simplemente S,T K@sin nombrar explícitamente los caracteres de sustitución que se pueden deducir trivialmente de eso.
Arnauld
@Arnauld tienes toda la razón, me perdí eso, pero voy a dejar la pregunta como está, en caso de que alguien haya comenzado a escribir su respuesta.
Charlie

Respuestas:

3

JavaScript (ES6), 168 167 bytes

Devuelve una matriz de dos cadenas: [dictionary, compressed_string].

s=>[(a=(s=s.replace(/\d+/g,n=>C(n|64),C=String.fromCharCode)).match(/../g)).map(v=>s.split(v)[a[v]||3]>=''?D+=v+(a[v]=C(i++)):0,i=97,D='')&&D,a.map(v=>a[v]||v).join``]

Casos de prueba

Arnauld
fuente
3

Python 2 , 269 280 268 266 bytes

No pasa nada lujoso aquí. Buena oportunidad para usar algunas expresiones regulares simples.

La primera versión falló para cadenas que contenían caracteres especiales que fueron interpretados dentro de la expresión regular. La segunda versión (usando re.escape) funciona con todos los casos de prueba. Esa corrección costó 11 bytes.

La segunda versión no asignó caracteres de sustitución en orden, como se requiere en la especificación del problema y como lo señaló @CarlosAlejo. Entonces, de vuelta al tablero de dibujo.

Versión corregida, más golfizada

  • -6 bytes guardados al no imprimir la salida en dos líneas
  • +3 bytes: cambiar a sustituciones de código a través de una cadena para permitir cumplir el desafío como se especifica.
  • -4 bytes: como ya no estoy llamando a re.findall dos veces, no necesito cambiarle el nombre
  • -5 bytes: cambio de bucles for a bucles while.
  • -2 bytes gracias a @Comrade Sparkle Pony
import re
S=re.sub
b=a=input()
for i in re.findall('\d{1,2}',a):
 b=S(i, chr(64+int(i)),b)
n,s,p=96,'',0
while p<len(b):
 c=b[p:p+2];f=b.count(c)
 if f>2and not c in s:n+=1;s+=c+chr(n)
 p+=2
p=0
while p<len(s):k=s[p:p+2];v=s[p+2];b=S(re.escape(k),v,b);p+=3
print s,b

Pruébalo en línea!

CCB60
fuente
Ya casi está allí, tenga en cuenta que los grupos en el segundo paso no se crean en el orden correcto (ver ejemplo). Los grupos deben crearse en orden de aparición, por lo que el primero debe ser O,a.
Charlie
@CarlosAlejo No lo había notado como un requisito, ya que las sustituciones son arbitrarias, desde un punto de vista funcional. Los diccionarios predeterminados de Python, una forma natural de implementar esto, no están ordenados. Habrá que tener en cuenta otras posibles estructuras de datos ....
CCB60
¿No podría guardar algunos bytes usando b=a=input()y n,s,p=96,'',0?
Camarada SparklePony
\d+sería una expresión regular más corta para usar. De todos modos, nunca superarás los 26, así que no hay razón para asegurarte de que sean específicamente de 1 a 2 dígitos. Además, el uso re.escapesignifica que una cadena básica replacetermina un poco más corta: 253 bytes
Value Ink
0

Lua, 215 bytes

Solo un poco de coincidencia de patrones.

Creo que Lua está subestimada cuando se trata de jugar al golf ... ¡mira todas esas declaraciones juntas!

g,c=string.gsub,string.char
u=g(arg[1],"%d%d?",function(n)return c(n+64)end)l,d=97,""g(u,"..",function(m)n,e=0,g(m,".", "%%%0")g(u,e,function()n=n+1 end)if n>2 then
l,s=l+1,c(l)d,u=d..m..s,g(u,e,s)end
end)print(u,d)
Trebuchette
fuente
0

Python 2 , 186 bytes

from re import*
S=sub('\d+',lambda m:chr(int(m.group(0))+64),input())
Q=[]
for p in findall('[A-Z].',S):
 if S.count(p)>2:a=chr(len(Q)+97);Q+=[p+a];S=sub(escape(p),a,S)
print''.join(Q),S

Esperaba encontrar finalmente uso para re.subn: C

# first step - convert all numbers to uppercase letters
S=sub('\d+',lambda m:chr(int(m.group(0))+64),input())
# empty list to hold encoding of second step
Q=[]
# find every encoded pair (uppercase letter and some char)
for p in findall('[A-Z].',S):
 # if it occures 3 or move times
 if S.count(p)>2:
  # get lowercase letter to substitute with
  a=chr(len(Q)+97)
  # store encoding into list
  Q+=[p+a]
  # update string - substitute pair with lowercase letter
  S=sub(escape(p),a,S)
# output
# encodings of second step, space, result
# if nothing was compressed at step 2, space would prepend result (of step 1)
print''.join(Q),S

Comprimido en el paso 2

No comprimido en el paso 2


Python 2 , 246 bytes

Todo el segundo paso hecho en repl lambda de re. Solo por diversión.

from re import*
Q=[]
S=sub('\d+',lambda m:chr(int(m.group(0))+64),input())
S=sub('[A-Z].',lambda m:(lambda m:S.count(m)>2and(m in Q or not Q.append(m))and chr(Q.index(m)+97)or m)(m.group(0)),S)
print''.join(Q[i]+chr(i+97)for i in range(len(Q))),S

Pruébalo en línea!

Zarigüeya muerta
fuente
0

Perl 5 -pl , 81 bytes

s/\d+/chr$&+64/ge;$b=a;for$a(/([A-Z].)(?=.*\1.*\1)/g){s/\Q$a/$b/g&&($\.=$a.$b++)}

Pruébalo en línea!

Imprime la cadena codificada en la primera línea, la triple en la segunda línea

Xcali
fuente
0

Ruby -p , 133 bytes

gsub(/(\d+)(.)/){(64+$1.to_i).chr+$2}
c=?`;s=''
$_.scan(/(..)(?=.*\1.*\1)/){s+=$&+c.succ!if !s[$&]}
puts s.scan(/(..)(.)/){gsub$1,$2}

Pruébalo en línea!

Tinta de valor
fuente