Generar un rectángulo a partir de una especificación


14

Introducción

Este desafío está inspirado en Grime , mi lenguaje de coincidencia de patrones 2D. Básicamente, se le da una "gramática" que describe cuadrículas de caracteres bidimensionales, y su trabajo es generar una cuadrícula de acuerdo con la gramática. Además, la cuadrícula debe ser lo más pequeña posible en cierto sentido débil.

Entrada

Su entrada es una cadena que contiene caracteres ASCII en minúsculas y los símbolos |y -. Para simplificar, la entrada no contiene caracteres en minúsculas repetidos. La cadena es una especificación para una clase de cuadrículas rectangulares de caracteres, y se analiza de izquierda a derecha utilizando una pila de la siguiente manera.

  • Dado un carácter en minúscula c, empuje a la pila una m×ncuadrícula del personaje c, para cualquiera m, n ≥ 1.
  • Dada una tubería |, revienta dos cuadrículas Ay Bdesde la pila ( Bestaba arriba), y empuja la cuadrícula ABobtenida concatenando Ba la derecha de A. Esto requiere eso Ay Btener la misma altura.
  • Dado un guión -, haga estallar dos cuadrículas Ay Bdesde la pila ( Bestaba en la parte superior), y empuje la cuadrícula A/Bobtenida concatenando Bhasta el fondo de A. Esto requiere eso Ay Btener el mismo ancho.

Se garantiza que para algunas elecciones my nrealizadas durante el proceso de análisis (que puede ser diferente para cada letra), la especificación de entrada describe correctamente algún rectángulo, que se deja en la pila al final.

Salida

Su salida es una cuadrícula rectangular de caracteres especificados por la entrada. La cuadrícula debe ser mínima en el sentido de que eliminar cualquier fila o columna la invalidaría. Puede devolver una cadena separada por una nueva línea (con o sin una nueva línea final), una matriz 2D de caracteres o una matriz de cadenas, según el formato más conveniente.

Tenga en cuenta que no es necesario que procese la entrada exactamente como se describe anteriormente; Lo único importante es que su salida es correcta.

Ejemplo

Considere la especificación

par-s||e-

Primero, elegimos empujar un 1×2rectángulo de py 1×1rectángulos de ay r(la razón de esto se aclarará más adelante). Entonces, nos pop las ay los rrectángulos, y empujar a sus concatenación verticales

a
r

Luego, empujamos un 1×2rectángulo de s, lo sacamos y el rectángulo de arriba, y empujamos su concatenación horizontal

as
rs

Luego hacemos estallar ese rectángulo y el prectángulo, y empujamos su concatenación

pas
prs

Finalmente, empujamos un 3×1rectángulo de e, lo sacamos y el rectángulo de arriba, y empujamos la concatenación vertical

pas
prs
eee

Esta es la salida del programa, o al menos una de las posibilidades. Tenga en cuenta que aunque

ppas
ppas
pprs
eeee

también es generado por la especificación, no es una salida válida, ya que muchas de las filas y columnas podrían eliminarse.

Como un ejemplo más sutil, considere

co|m|p|il|e|r|-

Esta especificación genera el rectángulo

comp
iler

que es una salida válida Sin embargo, también genera

commp
iiler

que también es válido, ya que no se puede eliminar una sola fila o columna sin invalidarlo.

Reglas

Puedes dar un programa completo o una función. El conteo de bytes más bajo gana, y las lagunas estándar no se permiten.

Casos de prueba extra

Puede usarlos para probar su programa.

Input:
a
Output:
a

Input:
co|mp|l|-ex|i|f|-y|
Example output:
cccoy
mplly
exify

Input:
ja-r|g-o|ni-|ze|d-|
Example output:
jronze
arondd
ggoidd

Input:
un|co|p-yr|i|gh-t-ab|-|le-||-
Example output:
unnnnnnn
coyriggl
ppyrihhe
ppyritte
ppyriabe

¿De dónde vienen nym?
seequ

¿Puede ser estático o tiene que ser alguna forma de entrada?
seequ

@Sieg ny mse eligen de forma no determinista. Se garantiza que existen valores adecuados para ellos, pero es el trabajo de su programa encontrarlos.
Zgarb

En realidad no define lo que son.
seequ

un|co|p-|yr|i|gh--t-ab|-|le-||-Es imposible ser válido. El último -tiene una aridad de 2, mientras que solo hay 1 elemento en la pila.
orlp

Respuestas:


6

K, 123110 bytes

Utilicé un enfoque similar a la solución de cartón_box.

r:{y,x#,*|y};h:{t:(#x)|#y;r[t-#x;x],'r[t-#y]y};a:{(,x .|2#y),2_ y};*(){(a[{+h[+x;+y]}]x;a[h]x;(,,y),x)"-|"?y}/

Este programa es una serie de definiciones auxiliares seguidas de una función tácita que toma una cadena como argumento correcto. Reformatear para facilitar la lectura y asignar la función final como f:

r: {y,x#,*|y};                           / repeat last row x times
h: {t:(#x)|#y;r[t-#x;x],'r[t-#y;y]};     / append horizontal
v: {+h[+x;+y]};                          / append vertical
a: {(,x[y@1;y@0]),2_ y};                 / pop two values, concat

f: *(){:[y="-";a[v;x]; y="|";a[h;x]; (,,y),x]}/;

Use ejemplo:

  f "ja-r|g-o|ni-|ze|d-|"
("jronze"
 "aroidd"
 "ggoidd")

Probado con Kona, pero también funcionará en OK si reemplaza el :en la definición de fa $- k5 cambió la sintaxis de "cond".

Un punto clave es reconocer que hacer un apéndice vertical es la transposición del apéndice horizontal de la transposición de ambas matrices. (Ver definición v.) Creo que todavía hay espacio para exprimir algunos caracteres aquí y allá. Si alguien está interesado en una explicación más detallada, puedo proporcionar una.

editar:

Se actualizó el programa en la parte superior de esta entrada. Versión sin golf:

r: {y,x#,*|y};                           / repeat row x times
h: {t:(#x)|#y;r[t-#x;x],'r[t-#y;y]};     / append horizontal
v: {+h[+x;+y]};                          / append vertical
a: {(,x .|2#y),2_ y};                    / apply a concat
f: *(){(a[v]x;a[h]x;(,,y),x)"-|"?y}/;

Las optimizaciones de longitud notables incluyen el uso de "aplicar punto" a, reemplazando el "cond" con la indexación de lista f(menos eficiente, pero más corta) y reemplazando los términos del formulario a[b;c]en a[b]cdonde lo permita la agrupación. Como ya no uso "cond" ni ninguna primitiva que sea diferente entre k3 y k5, esta versión ahora funciona en oK sin modificación.


¡Felicitaciones por ganar la recompensa!
Zgarb 01 de

¡Gracias! Fue un problema interesante que cedió bastante bien a K. Hubiera sido interesante ver intentos en J o APL para comparar.
JohnE

4

Prólogo, 539 bytes

:-lib(ic).
:-lib(util).
b(A,B,C):-between(A,B,C).
g(S):-string_list(S,L),p(L,[]).
w(h(L,R):_:_,I,J):-w(L,I,J);L=_:W:_,X is I-W,w(R,X,J).
w(v(U,D):_:_,I,J):-w(U,I,J);U=_:_:H,Y is J-H,w(D,I,Y).
w(f(C):W:H,I,J):-b(1,W,I),b(1,H,J),char_code(S,C),put_char(S).
p([],[S]):-term_variables(S,V),S=_:X:Y,labeling(V),!,b(1,Y,J),(b(1,X,I),w(S,I,J);nl),fail.
p([124|T],[Q,Z|R]):-!,Q=_:WA:H,Z=_:WB:H,W #= WA+WB,p(T,[h(Z,Q):W:H|R]).
p([45|T],[Q,Z|R]):-!,Q=_:W:HA,Z=_:W:HB,H #= HA+HB,p(T,[v(Z,Q):W:H|R]).
p([C|T],R):-!,[H,W] #:: 1..100,p(T,[f(C):W:H|R]).

Explicación

Comenzamos con un predicado g, que toma una cadena, la convierte como una lista de caracteres y llama al ppredicado (parse) con una pila vacía como segundo argumento.

Predicate se pllama a sí mismo de forma recursiva con una pila adecuadamente modificada (busque [H|T]patrones de desestructuración y de construcción) Cuando se invoca en el caso base, donde la lista de entrada está vacía, pimprime el elemento único de la pila. Si la pila tiene menos o más de un elemento en este punto, significa que tenemos una cadena de entrada vacía, una cadena de entrada incorrecta o un error (con una cadena vacía, el predicado falla (dice Prolog No), pero no se imprime nada, lo cual está bien, ya que no debemos imprimir nada para cadenas vacías).

Resolviendo

La pila contiene una descripción de los rectángulos construidos, indicada S:W:H, donde Ses una representación simbólica del rectángulo, Wsu ancho y Hsu altura (nota, A:Bes azúcar sintáctico para la :(A,B)tupla con un functor llamado :; es más corto de escribir que tener una tupla con notación de prefijo).

Con las especificaciones Ay Bsub-rectángulo, Spuede ser:

  • h(A,B) : concat horizontal de A y B
  • v(A,B) : concat vertical de A y B
  • f(C) : rellene con C, donde C es un código de caracteres

Los anchos y las alturas de las cuadrículas son variables de programación de restricciones: durante la concatenación vertical (resp. Horizontal), el ancho (resp. Altura) de los rectángulos manipulados se unifica, mientras que la altura resultante (resp. Ancho) se limita a ser la suma de altura de cada subcuadrícula (ancho de resp.)

El paso de etiquetado al final del proceso instancia las variables mientras respeta las restricciones, utilizando los valores mínimos posibles (esta es una propiedad del orden por el que se prueban las soluciones).

Podría haber obtenido una respuesta más corta usando el mismo razonamiento que se hace en otras respuestas, sin restricciones, pero ahora es demasiado tarde.

Tenga en cuenta también que debido a que el dominio predeterminado para las variables está establecido en 1..100, existe una limitación sobre los posibles tamaños de cuadrículas. El límite superior se puede cambiar si es necesario. Las implicaciones de rendimiento de esto son que podría tomar mucho tiempo determinar que una solución en particular no admite ninguna solución. Dije " podría " porque es probable que las restricciones reduzcan drásticamente la búsqueda exponencial. Si encuentra una cadena de entrada que es difícil / costosa de rechazar, por favor comparta.

Impresión

La parte de impresión es interesante porque hay una especie de algoritmo de proyección de rayos sobre la estructura: itero sobre cada celda de la cuadrícula resultante, de punto (1,1)a punto (W,H)y llamo al wpredicado para imprimir el contenido de la cuadrícula en el árbol principal, en esta ubicación (por supuesto, se imprime una nueva línea después de procesar cada línea).

En w, las posiciones son relativas a la cuadrícula actual (la cuadrícula raíz define coordenadas absolutas).

Cuando imprimo una h(A,B)estructura en un punto (X,Y), imprimo incondicionalmente en ambas ramas:

  • en cuadrícula Aen el punto (X,Y), y
  • en la cuadrícula Ben el punto (H,Y), donde Hes Xmenos el ancho de A.

Las ramas de la hoja del árbol de la cuadrícula f(C), finalmente imprimen el carácter C, si la ubicación relativa está dentro de la cuadrícula, o no hacen nada. Así es como puedo imprimir el contenido de la cuadrícula en la secuencia de salida, de arriba a abajo, de izquierda a derecha. No se producen matrices reales.

Pruebas

t("ja-r|g-o|ni-|ze|d-|").
t("un|co|p-yr|i|gh-t-ab|-|le-||-").
t("co|mp|l|-ex|i|f|-y|").
t("a").

tt :- t(X),nl,g(X).
tt.

Prueba de carrera:

[eclipse] tt.

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe

cccoy
mmply
exify

a

Yes (0.00s cpu)

+1 No actual arrays are produced.así es como debe hacerse. Exagerar en este caso, ya que la gramática es muy simple y hay atajos.
edc65

@ edc65 Sí, es exagerado. Pero como se trata de codegolf, intenté minimizar el tamaño, y manipular las matrices habría sido demasiado detallado.
coredump

3

Python 2.7, 259

z=zip
def p(a,b):
 s,l=sorted([a,b],key=len)
 s+=([s[-1]]*(len(l)-len(s)))
 return z(*(z(*a)+z(*b)))
g=lambda s,t=[]:s and(s[0]=='-'and g(s[1:],t[:-2]+[z(*p(z(*t[-2]),z(*t[-1])))])or(s[0]=='|'and g(s[1:],t[:-2]+[p(t[-2],t[-1])])or g(s[1:],t+[[s[0]]])))or t[0]

ges una función que toma una especificación y proporciona una matriz 2D de caracteres. Si desea una versión más fácil de usar, agregue esta línea para que tome una especificación de stdin e imprima la cuadrícula:

print'\n'.join(''.join(s)for s in g(raw_input()))

Casos de prueba

Input:
a
Output:
a
==========
Input:
co|mp|l|-ex|i|f|-y|
Output:
coooy
mplly
exify
==========
Input:
ja-r|g-o|ni-|ze|d-|
Output:
jronze
aroidd
ggoidd
==========
Input:
un|co|p-yr|i|gh-t-ab|-|le-||-
Output:
unnnnnnn
coyriggl
ppyrihhe
ppyritte
ppyriabe

Explicación

La estrategia es simple: si una cuadrícula Ges válida para una especificación S, la repetición de la columna más a la derecha de Gtambién proporciona una especificación válida para S, y lo mismo es cierto con la repetición de la fila inferior (la prueba de esto es por inducción estructural activada S). Por lo tanto, cuando queremos concatenar dos rectángulos, simplemente podemos agregar la última columna / fila del más pequeño hasta que coincidan en tamaño (esto es lo que hace la función p).


3

Haskell, 388 367 352 bytes

data C=L{c::Char}|N{t::Int,w::Int,h::Int,l::C,r::C}
q=replicate
[]#[x]=x
(c:i)#(b:a:s)|c=='-'=i#(N 1(max(w a)$w b)(h a+h b)a b:s)|c=='|'=i#(N 2(w a+w b)(max(h a)$h b)a b:s)
(c:i)#s=i#(N 0 1 1(L c)(L c):s)
p i|t i==0=q(h i)$q(w i)$c$l i|t i==2=zipWith(++)(p(l i){h=h i})$p(r i){h=h i,w=w i-w(l i)}|1<2=p(l i){w=w i}++p(r i){w=w i,h=h i-h(l i)}
f=p.(#[])

Uso: f "par-s||e-"->["pas","prs","eee"]

Prueba de funcionamiento con bonita impresión:

> putStr $ unlines $ f "par-s||e-"
pas
prs
eee

> putStr $ unlines $ f "co|m|p|il|e|r|-"
comp
iler

> putStr $ unlines $ f "a"
a

> putStr $ unlines $ f "co|mp|l|-ex|i|f|-y|"
coooy
mplly
exify

> putStr $ unlines $ f "ja-r|g-o|ni-|ze|d-|"
jronze
aroidd
ggoidd

> putStr $ unlines $ f "un|co|p-yr|i|gh-t-ab|-|le-||-"
unnnnnnn
coyriggl
ppyrihhe
ppyritte
ppyriabe

Cómo funciona: la función #analiza la cadena de entrada en la estructura de árbol, Cque es una hoja que Lcontiene el carácter para imprimir o un nodo N. Npuede ser a) una combinación de lado a lado ( t==2), b) una combinación de arriba a abajo ( t==1) o c) un cuadrado de una sola letra ( t==0). Todos los nodos tienen un campo de ancho y alto y un hijo izquierdo y derecho. Después del análisis, pimprime el nodo raíz restante ajustando recursivamente el tamaño (ancho x alto) de sus nodos secundarios y uniéndolos.

Editar: salida como una lista de líneas en lugar de una bonita impresión


1

JavaScript (ES6), 283 295

Editar ahora esta solución JS (muy golfizada) es al menos más corta que la solución Python de referencia (bastante golfable).

Al igual que cartón_box, solo repite la columna de la izquierda o la fila superior.

F=w=>(
s=[t=1,l='length'],
[for(c of w)(
  b=s[t],a=s[--t],
  c>'z'?
    s[t]=(G=(a,b,m=b[l]-a[l])=>m?m>0?G([a[0],...a],b):G(a,[b[0],...b]):a.map((r,i)=>r+b[i]))(a,b)
  :c<'a'?
    s[t]=a.map(r=>r[m=b[0][l]-r[l],0].repeat(m>0&&m)+r).concat(b.map(r=>r[0].repeat(m<0&&-m)+r))
  :s[t+=2]=[c]
)],
s[t].join('\n'))

Sin golf Esta es mi primera solución sin golf.

F=sp=>{
  s=[]
  for(c of sp){
    a=s.pop(b=s.pop())
    if (c > 'z')
    {
      l = a.length
      m = b.length
      for(; l-m ;)
        l < m ? l = a.unshift(a[0]) : m = b.unshift(b[0])
      s.push(a.map((r,i) => r + b[i]))
    }
    else if (c < 'a')
    {
      l = a[0].length
      m = b[0].length
      s.push(
        a.map(r => r[0].repeat(l < m ? m-l : 0) + r)
        .concat(b.map( r => r[0].repeat( l > m ? l-m : 0) + r))
      )
    }
    else 
    {
      s.push(a,b,[c])
    }
  }
  return s.pop().join('\n')
}

Prueba en la consola Firefox / FireBug

;['par-s||e-','co|m|p|il|e|r|-','co|mp|l|-ex|i|f|-y|',
 'ja-r|g-o|ni-|ze|d-|','un|co|p-yr|i|gh-t-ab|-|le-||-']
.forEach(w=>console.log(F(w)))

Salida

pas
prs
eee

comp
iler

cccoy
mmply
exify

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe

0

Python 3, 251 bytes

Aquí está la respuesta de referencia que prometí, jugar golf un poco más.

T=lambda m:list(map(list,zip(*m)))
E=lambda a,b:a[:1]*(len(b)-len(a))+a
H=lambda a,b:[d+c for c,d in zip(E(a,b),E(b,a))]
s=[]
for k in input():s=k>"z"and[H(*s[:2])]+s[2:]or k<"a"and[T(H(*map(T,s[:2])))]+s[2:]or[[[k]]]+s
for r in s[0]:print("".join(r))

Este es un programa completo que toma la cadena de STDIN e imprime en STDOUT. El enfoque es el mismo que el de cartón_box: inserta una matriz 1x1 para un personaje y duplica filas si es necesario para la concatenación.

$ echo "par-s||e-" | python3 gr.py
pas
prs
eee

Explicación detallada

  • Ttranspone una lista dada de listas. La mayor parte del trabajo se realiza mediante zip(*m)el intercambio de filas en columnas, el resto solo convierte el resultado en una lista de listas, ya quezip devuelve un generador de tuplas.
  • E(a,b)vuelve acon su primer elemento repetido suficientes veces para que coincida con la longitud de b. Tenga en cuenta que multiplicar una lista por un número negativo da la lista vacía, por lo que si bes más corto que a, esto devuelvea .
  • H(a,b)devuelve la concatenación horizontal de ay b, alargándose la más corta porE si es necesario.
  • s es la pila
  • En el forbucle, iteramos sobre la cadena de entrada y la reemplazamos spor un nuevo valor: si es |(mayor que z), sacamos dos valores y empujamos sus H, si es -(menor quea ), sacamos dos valores, transponemos, alimentamos H, transponer de nuevo y empujar el resultado, y de lo contrario empujar una matriz 1x1 con la letra.
  • Finalmente, imprimimos el primer elemento de s.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.