Genera un rettangolo da una specifica


14

introduzione

Questa sfida è ispirata a Grime , il mio linguaggio di corrispondenza dei motivi 2D. Fondamentalmente, ti viene data una "grammatica" che descrive griglie bidimensionali di caratteri e il tuo compito è generare una griglia secondo la grammatica. Inoltre, la griglia dovrebbe essere il più piccola possibile in un certo senso debole.

Ingresso

Il tuo input è una stringa contenente caratteri ASCII minuscoli e i simboli |e -. Per semplicità, l'input non contiene caratteri minuscoli ripetuti. La stringa è una specifica per una classe di griglie rettangolari di caratteri e viene analizzata da sinistra a destra usando una pila come segue.

  • Dato un carattere minuscolo c, spingi in pila una m×ngriglia del personaggio c, per qualsiasi m, n ≥ 1.
  • Dato un pipe |, fai scoppiare due griglie Ae Bdalla pila ( Bera in cima), e spingi la griglia ABottenuta concatenando Ba destra di A. Ciò richiede questo Ae Bavere uguale altezza.
  • Dato un trattino -, fai scoppiare due griglie Ae Bdalla pila ( Bera in cima) e spingi la griglia A/Bottenuta concatenando Bsul fondo di A. Ciò richiede che Ae Babbiano la stessa larghezza.

È garantito che per alcune scelte di me nfatte durante il processo di analisi (che può essere diverso per ogni lettera), la specifica di input descrive correttamente un rettangolo, che viene lasciato in pila alla fine.

Produzione

L'output è una griglia rettangolare di caratteri specificata dall'input. La griglia deve essere minima, nel senso che la rimozione di qualsiasi riga o colonna la renderebbe non valida. È possibile restituire una stringa separata da una nuova riga (con o senza una nuova riga finale), una matrice 2D di caratteri o una matrice di stringhe, a seconda di quale sia il formato più conveniente.

Si noti che non è necessario elaborare l'input esattamente come descritto sopra; l'unica cosa importante è che l'output sia corretto.

Esempio

Considera le specifiche

par-s||e-

Innanzitutto, scegliamo di premere un 1×2rettangolo di pe 1×1rettangoli di ae r(la ragione di ciò sarà chiara più avanti). Poi, abbiamo pop le ae rrettangoli, e spingere il loro concatenamento verticale

a
r

Successivamente, spingiamo un 1×2rettangolo di s, lo pop e il rettangolo sopra e spingiamo la loro concatenazione orizzontale

as
rs

Quindi pop quel rettangolo e il prettangolo e spingiamo la loro concatenazione

pas
prs

Infine, spingiamo un 3×1rettangolo di e, lo pop e il rettangolo sopra e spingiamo la concatenazione verticale

pas
prs
eee

Questo è l'output del programma, o almeno una delle possibilità. Notalo anche se

ppas
ppas
pprs
eeee

viene inoltre generato dalla specifica, non è un output valido, poiché è possibile rimuovere molte righe e colonne.

Come esempio più sottile, considera

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

Questa specifica genera il rettangolo

comp
iler

che è un output valido. Tuttavia, genera anche

commp
iiler

anche questo è valido, poiché nessuna riga o colonna può essere rimossa senza invalidarla.

Regole

Puoi dare un programma completo o una funzione. Vince il conteggio di byte più basso e non sono consentite scappatoie standard.

Casi di prova extra

Puoi usarli per testare il tuo programma.

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

Da dove provengono?
Seequ,

Può essere statico o deve essere una forma di input?
Seequ,

@Sieg ne msono scelti in modo non deterministico. È garantito che esistano valori adeguati per loro, ma è compito del tuo programma trovarli.
Zgarb,

In realtà non definisci cosa sono.
Seequ,

un|co|p-|yr|i|gh--t-ab|-|le-||-è impossibile essere validi. L'ultimo -ha un'arità di 2, mentre nello stack è presente solo 1 elemento.
orlp

Risposte:


6

K, 123 110 byte

Ho usato un approccio simile alla soluzione di cartone_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}/

Questo programma è una serie di definizioni di aiuto seguite da una funzione tacita che accetta una stringa come argomento corretto. Riformattazione per leggibilità e assegnazione della funzione finale come 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]}/;

Usa esempio:

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

Testato usando Kona, ma funzionerà anche in oK se si sostituisce il :nella definizione di fcon a $- k5 ha cambiato la sintassi di "cond".

Un punto chiave è riconoscere che fare un'appendice verticale è la trasposizione dell'appendice orizzontale della trasposizione di entrambe le matrici. (Vedi definizione v.) Penso che ci sia ancora spazio per spremere alcuni personaggi qua e là. Se qualcuno è interessato a una spiegazione più dettagliata, posso fornirne una.

modificare:

Aggiornato il programma nella parte superiore di questa voce. Versione non golfata:

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

Notevoli ottimizzazioni della lunghezza includono l'uso di "punto apply" in a, la sostituzione di "cond" con l'indicizzazione dell'elenco in f(meno efficiente, ma più breve) e la sostituzione dei termini del modulo a[b;c]in a[b]cdove consentito dal raggruppamento. Dal momento che non sto più usando "cond" o qualsiasi primitiva diversa tra k3 e k5 questa versione ora funziona in oK senza modifiche.


Congratulazioni per aver vinto la taglia!
Zgarb,

Grazie! È stato un problema interessante che ha fruttato abbastanza bene a K. Sarebbe stato interessante vedere i tentativi di confronto tra J o APL.
JohnE

4

Prolog, 539 byte

:-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]).

Spiegazione

Iniziamo con predicato g, che accetta una stringa, la converte in un elenco di caratteri e chiamiamo il ppredicato (analisi) con uno stack vuoto come secondo argomento.

Predicate si pchiama ricorsivamente con uno stack opportunamente modificato (cerca [H|T]schemi di destrutturazione e costruttori). Quando viene chiamato nel caso base, in cui l'elenco di input è vuoto, pstampa l'elemento univoco dello stack. Se lo stack ha meno o più di un elemento a questo punto, significa che abbiamo una stringa di input vuota, una stringa di input errata o un bug (con una stringa emtpy, il predicato fallisce (dice Prolog No), ma non viene stampato nulla, il che va bene, dal momento che non dovremmo stampare nulla per stringhe vuote).

soluzione

La pila contiene una descrizione dei rettangoli costruiti, denotati S:W:H, dove Sè una rappresentazione simbolica del rettangolo, della Wsua larghezza e della Hsua altezza (nota, A:Bè zucchero sintattico per la :(A,B)tupla con un funzione chiamato :; è solo più breve da scrivere che avere una tupla con notazione prefisso).

Con Ae le Bspecifiche del rettangolo secondario, Spossono essere:

  • h(A,B) : concat orizzontale di A e B
  • v(A,B) : concat verticale di A e B
  • f(C) : riempire con C, dove C è un codice carattere

Le larghezze e le altezze delle griglie sono variabili di programmazione dei vincoli: durante la concatenazione verticale (o orizzontale), la larghezza (o l'altezza) dei rettangoli manipolati viene unificata, mentre l'altezza risultante (o la larghezza) viene vincolata per essere la somma di l'altezza di ogni sottogriglia (risp. larghezza).

La fase di etichettatura alla fine del processo istanzia le variabili nel rispetto dei vincoli, utilizzando i valori minimi possibili (questa è una proprietà dell'ordine mediante il quale vengono provate le soluzioni).

Avrei potuto ottenere una risposta più breve usando lo stesso ragionamento che viene fatto in altre risposte, senza vincoli, ma ora è troppo tardi.

Si noti inoltre che, poiché il dominio predefinito per le variabili è impostato su 1..100, esiste una limitazione sulle possibili dimensioni delle griglie. Il limite superiore potrebbe essere modificato se necessario. Le conseguenze in termini di prestazioni di ciò sono che potrebbe essere necessario molto tempo per determinare che una determinata soluzione non ammette alcuna soluzione. Ho detto " potrebbe " perché è probabile che i vincoli potano drasticamente la ricerca esponenziale. Se trovi una stringa di input che è difficile / costosa da rifiutare, ti preghiamo di condividere.

Stampa

La parte di stampa è interessante perché esiste una sorta di algoritmo di ray-casting sulla struttura: eseguo l'iterazione su ogni cella della griglia risultante, da un punto (1,1)all'altro (W,H)e chiamo il wpredicato per stampare il contenuto della griglia nell'albero principale, in questa posizione (ovviamente, una riga nuova viene stampata dopo l'elaborazione di ogni riga).

In w, le posizioni sono relative alla griglia corrente (la griglia principale definisce le coordinate assolute).

Quando stampo una h(A,B)struttura in quel punto (X,Y), stampo incondizionatamente in entrambi i rami:

  • in griglia Aal punto (X,Y), e
  • nella griglia Bnel punto (H,Y), dove Hè Xmeno la larghezza di A.

I rami delle foglie dell'albero della griglia f(C), infine, stampano il personaggio C, se la posizione relativa è all'interno della griglia, o non fanno nulla. Ecco come posso stampare il contenuto della griglia sul flusso di output, dall'alto verso il basso, da sinistra a destra. Non vengono prodotti array effettivi.

test

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.

Esecuzione del test:

[eclipse] tt.

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe

cccoy
mmply
exify

a

Yes (0.00s cpu)

+1 No actual arrays are produced.è così che dovrebbe essere fatto. Overkill in questo caso, poiché la grammatica è così semplice e ci sono scorciatoie.
edc65,

@ edc65 Sì, è eccessivo. Ma dal momento che è codegolf, ho cercato di ridurre al minimo le dimensioni e manipolare le matrici sarebbe stato troppo prolisso.
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]

gè una funzione che accetta una specifica e fornisce una matrice 2D di caratteri. Se vuoi una versione più user-friendly, aggiungi questa riga per far sì che prenda una specifica da stdin e stampi la griglia:

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

Casi test

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

Spiegazione

La strategia è semplice: se una griglia Gè valida per una specifica S, la ripetizione della colonna più a destra di Gfornisce anche una specifica valida S, e lo stesso vale per la ripetizione della riga inferiore (la prova di ciò è data dall'induzione strutturale attivata S). Pertanto, quando vogliamo concatenare due rettangoli, possiamo semplicemente aggiungere l'ultima colonna / riga di quella più piccola fino a quando non corrispondono in termini di dimensioni (questo è ciò che fa la funzione p).


3

Haskell, 388 367 352 byte

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"]

Test eseguito con una stampa carina:

> 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

Come funziona: la funzione #analizza la stringa di input nella struttura ad albero Cche è una foglia che contiene Lil carattere da stampare o un nodo N. Npuò essere a) un join side-by-side ( t==2), b) un join top-bottom ( t==1) oc) un quadrato di una sola lettera ( t==0). Tutti i nodi hanno un campo di larghezza e altezza e un figlio sinistro e destro. Dopo l'analisi, pstampa il nodo radice rimanente regolando ricorsivamente la dimensione (larghezza x altezza) dei suoi nodi figlio e unendoli.

Modifica: output come un elenco di linee invece di una bella stampa


1

JavaScript (ES6), 283 295

Modifica Ora questa soluzione JS (fortemente giocata a golf) è almeno più corta della soluzione Python di riferimento (piuttosto giocabile).

Simile abox_box, basta ripetere la colonna più a sinistra o la riga più in alto.

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 Questa è la mia prima soluzione 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')
}

Test nella 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)))

Produzione

pas
prs
eee

comp
iler

cccoy
mmply
exify

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe

0

Python 3, 251 byte

Ecco la risposta di riferimento che ho promesso, ho continuato a giocare a golf.

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

Questo è un programma completo che prende la stringa da STDIN e stampa su STDOUT. L'approccio è uguale a quello dibox_box: spingere un array 1x1 per un personaggio e, se necessario, duplicare le righe per la concatenazione.

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

Spiegazione dettagliata

  • Ttraspone un determinato elenco di elenchi. La maggior parte del lavoro viene eseguita zip(*m)scambiando righe in colonne, il resto sta semplicemente convertendo il risultato in un elenco di elenchi, poiché ziprestituisce un generatore di tuple.
  • E(a,b)ritorna acon il suo primo elemento ripetuto abbastanza volte da corrispondere alla lunghezza di b. Nota che moltiplicando un elenco per un numero negativo si ottiene un elenco vuoto, quindi se bè più corto di a, questo ritorna a.
  • H(a,b)restituisce la concatenazione orizzontale di ae b, mentre quella più corta viene allungata diE se necessario.
  • s è lo stack.
  • Nel forciclo, eseguiamo l'iterazione sulla stringa di input e la sostituiamo scon un nuovo valore: se è |(maggiore di z), popoliamo due valori e spingiamo i loro H, se è -(inferiore a a), popoliamo due valori, trasponiamo, feed a H, trasporre di nuovo e spingere il risultato, altrimenti spingere un array 1x1 con la lettera.
  • Infine, stampiamo il primo elemento di s.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.