Gerar um retângulo a partir de uma especificação

14

Introdução

Esse desafio é inspirado no Grime , minha linguagem de correspondência de padrões 2D. Basicamente, você recebe uma "gramática" que descreve grades bidimensionais de caracteres e seu trabalho é gerar uma grade de acordo com a gramática. Além disso, a grade deve ser a menor possível em um certo sentido fraco.

Entrada

Sua entrada é uma sequência que contém caracteres ASCII em minúsculas e os símbolos |e -. Para simplificar, a entrada não contém caracteres minúsculos repetidos. A sequência é uma especificação para uma classe de grades retangulares de caracteres e é analisada da esquerda para a direita usando uma pilha da seguinte maneira.

  • Dado um caractere minúsculo c, empurre para a pilha uma m×ngrade do caractere c, para qualquer m, n ≥ 1.
  • Dado um cano |, coloque duas grades Ae Bda pilha ( Bestava no topo) e empurre a grade ABobtida concatenando Bà direita de A. Isso requer isso Ae Btem altura igual.
  • Dado um hífen -, retire duas grades Ae Bda pilha ( Bestava no topo) e empurre a grade A/Bobtida concatenando Bpara o final de A. Isso requer isso Ae Btem largura igual.

É garantido que, para algumas escolhas feitas me nfeitas durante o processo de análise (que podem ser diferentes para cada letra), a especificação de entrada descreva corretamente algum retângulo, que é deixado na pilha no final.

Resultado

Sua saída é uma grade retangular de caracteres especificada pela entrada. A grade deve ser mínima no sentido de que remover qualquer linha ou coluna a tornaria inválida. Você pode retornar uma string separada por nova linha (com ou sem uma nova linha à direita), uma matriz 2D de caracteres ou uma matriz de cadeias, o que for o formato mais conveniente.

Observe que você não é obrigado a processar a entrada exatamente como descrito acima; a única coisa importante é que sua saída esteja correta.

Exemplo

Considere a especificação

par-s||e-

Primeiro, escolhemos empurrar um 1×2retângulo de p, e 1×1retângulos de ae r(a razão para isso ficará clara mais tarde). Então, nós estourar os ae rretângulos, e empurre a concatenação verticais

a
r

Em seguida, pressionamos um 1×2retângulo de s, pop e o retângulo acima, e pressionamos sua concatenação horizontal

as
rs

Em seguida, colocamos esse retângulo e o pretângulo e pressionamos sua concatenação

pas
prs

Por fim, pressionamos um 3×1retângulo de e, pop e o retângulo acima, e pressionamos a concatenação vertical

pas
prs
eee

Esta é a saída do programa, ou pelo menos uma das possibilidades. Observe que, embora

ppas
ppas
pprs
eeee

também é gerado pela especificação, não é uma saída válida, pois muitas das linhas e colunas podem ser removidas.

Como um exemplo mais sutil, considere

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

Esta especificação gera o retângulo

comp
iler

que é uma saída válida. No entanto, também gera

commp
iiler

o que também é válido, pois nenhuma linha ou coluna pode ser removida sem a invalidação.

Regras

Você pode dar um programa completo ou uma função. A contagem de bytes mais baixa vence e as brechas padrão não são permitidas.

Casos de teste extras

Você pode usá-los para testar seu 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
Zgarb
fonte
De onde vêm n?
seequ
Pode ser estático ou precisa ser algum tipo de entrada?
seequ
@Sieg ne msão escolhidos de forma não determinística. É garantido que existam valores adequados para eles, mas é tarefa do seu programa encontrá-los.
Zgarb 17/03/2015
Você realmente não define o que são.
seequ
un|co|p-|yr|i|gh--t-ab|-|le-||-é impossível ser válido. O último -tem uma área de 2, enquanto há apenas 1 elemento na pilha.
Ou orp

Respostas:

6

K, 123 110 bytes

Eu usei uma abordagem semelhante à solução de cartão_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 é uma série de definições auxiliares seguidas por uma função tácita que aceita uma string como argumento correto. Reformatação para facilitar a leitura e atribuir a função 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 exemplo:

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

Testado usando Kona, mas também funcionará em OK se você substituir o :na definição de fpor a $- k5 alterou a sintaxe de "cond".

Um ponto-chave é reconhecer que fazer um apêndice vertical é a transposição do apêndice horizontal da transposição de ambas as matrizes. (Veja a definição v.) Acho que ainda há espaço para espremer alguns caracteres aqui e ali. Se alguém estiver interessado em uma explicação mais detalhada, posso fornecer uma.

editar:

Atualizado o programa na parte superior desta entrada. Versão não destruída:

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}/;

As otimizações de tamanho notáveis ​​incluem o uso de "aplicação de ponto" a, substituindo o "cond" pela indexação de lista em f(menos eficiente, mas mais curta) e substituindo os termos do formulário a[b;c]para a[b]conde permitido pelo agrupamento. Como não estou mais usando "cond" ou quaisquer primitivas diferentes entre k3 e k5, esta versão agora funciona em OK sem modificações.

JohnE
fonte
Parabéns por ganhar a recompensa!
Zgarb 01/04
Obrigado! Foi um problema interessante que rendeu muito bem a K. Teria sido interessante ver tentativas em J ou APL para comparação.
Johne
4

Prolog, 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]).

Explicação

Começamos com predicado g, que pega uma string, converte-a como uma lista de caracteres e chamamos o ppredicado (analise) com uma pilha vazia como segundo argumento.

O predicado se pchama recursivamente com uma pilha adequadamente modificada (procure [H|T]padrões de desestruturação e construtor). Quando chamado no caso base, onde a lista de entrada está vazia, pimprime o elemento exclusivo da pilha. Se a pilha tiver menos ou mais de um elemento neste momento, significa que temos uma sequência de entrada vazia, uma sequência de entrada incorreta ou um bug (com uma sequência vazia, o predicado falha (Prolog diz No), mas nada é impresso, o que é bom, já que não devemos imprimir nada para cadeias vazias).

Resolução

A pilha contém uma descrição dos retângulos construídos, denotados S:W:H, onde Sé uma representação simbólica do retângulo, Wsua largura e Haltura (note que A:Bé um açúcar sintático para a :(A,B)tupla com um functor chamado :; é mais curto para escrever do que ter uma tupla com notação de prefixo).

Com Ae Bespecificações de sub-retângulo, Spode ser:

  • h(A,B) : concat horizontal de A e B
  • v(A,B) : concat vertical de A e B
  • f(C) : preencha com C, onde C é um código de caractere

As larguras e alturas das grades são variáveis ​​de programação de restrição: durante a concatenação vertical (resp. Horizontal), a largura (resp. Height) dos retângulos manipulados é unificada, enquanto a altura resultante (resp. Width) é restringida como a soma de a altura de cada sub-grade (resp. largura).

A etapa de rotulagem no final do processo instancia variáveis, respeitando as restrições, usando os valores mínimos possíveis (essa é uma propriedade da ordem pela qual as soluções são tentadas).

Eu poderia ter obtido uma resposta mais curta usando o mesmo raciocínio que é feito em outras respostas, sem restrições, mas agora é tarde demais.

Observe também que, como o domínio padrão das variáveis ​​está definido como 1..100, há uma limitação sobre os possíveis tamanhos de grades. O limite superior pode ser alterado se necessário. As implicações de desempenho disso são que pode levar muito tempo para determinar que uma solução específica não admite solução. Eu disse " poderia " porque é provável que as restrições afinem drasticamente a pesquisa exponencial. Se você encontrar uma string de entrada difícil / dispendiosa para rejeitar, compartilhe.

Impressão

A parte de impressão é interessante porque existe um tipo de algoritmo de projeção de raios sobre a estrutura: eu itero sobre cada célula da grade resultante, de ponto (1,1)a ponto (W,H)e chamo o wpredicado para imprimir o conteúdo da grade na árvore principal, em neste local (é claro, uma nova linha é impressa após o processamento de cada linha).

Em w, as posições são relativas à grade atual (a grade raiz define coordenadas absolutas).

Ao imprimir uma h(A,B)estrutura no ponto (X,Y), imprimo incondicionalmente nos dois ramos:

  • na grade Ano ponto (X,Y), e
  • na grade Bno ponto (H,Y), onde Hé Xmenos a largura de A.

Os galhos das folhas da árvore da grade f(C), finalmente, imprimem o caractere C, se a localização relativa estiver dentro da grade, ou não fazem nada. É assim que posso imprimir o conteúdo da grade no fluxo de saída, de cima para baixo, da esquerda para a direita. Nenhuma matriz real é produzida.

Testes

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.

Teste de corrida:

[eclipse] tt.

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe

cccoy
mmply
exify

a

Yes (0.00s cpu)
coredump
fonte
+1 No actual arrays are produced.é assim que deve ser feito. Exagero neste caso, como a gramática é muito simples e existem atalhos.
edc65
@ edc65 Sim, é um exagero. Mas como é um codegolf, tentei minimizar o tamanho e manipular matrizes teria sido muito detalhado.
Coredump 28/03
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]

gé uma função que aceita uma especificação e fornece uma matriz 2D de caracteres. Se você deseja uma versão mais amigável, adicione esta linha para obter uma especificação do stdin e imprimir a grade:

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

Casos de teste

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

Explicação

A estratégia é simples: se uma grade Gé válida para uma especificação S, a repetição da coluna mais à direita Gtambém fornece uma especificação válida para S, e o mesmo ocorre com a repetição da linha inferior (a prova disso é por indução estrutural S). Portanto, quando queremos concatenar dois retângulos, podemos simplesmente acrescentar a última coluna / linha da menor até que correspondam ao tamanho (é isso que a função p faz).

caixa de papelão
fonte
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"]

Teste executado com impressão bonita:

> 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

Como funciona: a função #analisa a string de entrada na estrutura da árvore, Cque é uma folha Lcontendo o caractere a ser impresso ou um nó N. Npode ser a) uma junção lado a lado ( t==2), b) uma junção de cima para baixo ( t==1) ou c) uma única letra quadrada ( t==0). Todos os nós têm um campo de largura e altura e um filho esquerdo e direito. Após a análise, pimprime o nó raiz restante ajustando recursivamente o tamanho (largura x altura) dos nós filhos e unindo-os.

Edit: output como uma lista de linhas em vez de uma bonita impressão

nimi
fonte
1

JavaScript (ES6), 283 295

Editar Agora, esta solução JS (altamente concentrada) é pelo menos menor que a solução Python de referência (bastante adaptável).

Semelhante a cartão_papel, apenas repetindo a coluna mais à esquerda ou a linha mais alta.

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

Ungolfed Esta é a minha primeira solução, ungolfed.

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

Teste no console 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)))

Resultado

pas
prs
eee

comp
iler

cccoy
mmply
exify

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe
edc65
fonte
0

Python 3, 251 bytes

Aqui está a resposta de referência que prometi, jogou um pouco mais.

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 é um programa completo que pega a string de STDIN e imprime em STDOUT. A abordagem é a mesma que a de paper_box: pressione uma matriz 1x1 para um caractere e duplique as linhas, se necessário, para concatenação.

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

Explicação detalhada

  • Ttranspõe uma determinada lista de listas. A maior parte do trabalho é feita zip(*m)trocando linhas por colunas; o restante é apenas convertendo o resultado em uma lista de listas, pois zipretorna um gerador de tuplas.
  • E(a,b)retorna acom seu primeiro elemento repetido vezes suficientes para corresponder ao comprimento de b. Observe que multiplicar uma lista por um número negativo fornece a lista vazia; portanto, se bfor menor que a, isso retornará a.
  • H(a,b)retorna a concatenação horizontal de ae b, a mais curta sendo prolongada, Ese necessário.
  • s é a pilha.
  • No forloop, iteramos sobre a string de entrada e substituímos spor um novo valor: se for |(maior que z), exibimos dois valores e pressionamos seus H; se for -(menor que a), exibimos dois valores, transpor, alimentar H, transponha novamente e empurre o resultado; caso contrário, empurre uma matriz 1x1 com a letra.
  • Finalmente, imprimimos o primeiro elemento de s.
Zgarb
fonte