Générer un rectangle à partir d'une spécification

14

introduction

Ce défi est inspiré de Grime , mon langage de correspondance de motifs 2D. Fondamentalement, vous disposez d'une "grammaire" qui décrit les grilles de caractères bidimensionnelles, et votre travail consiste à générer une grille en fonction de la grammaire. De plus, la grille doit être aussi petite que possible dans un certain sens faible.

Contribution

Votre entrée est une chaîne contenant des caractères ASCII minuscules et les symboles |et -. Par souci de simplicité, l'entrée ne contient pas de caractères minuscules répétés. La chaîne est une spécification pour une classe de grilles rectangulaires de caractères, et elle est analysée de gauche à droite en utilisant une pile comme suit.

  • Étant donné un caractère en minuscule c, poussez dans la pile une m×ngrille du caractère c, pour tout m, n ≥ 1.
  • Étant donné un tuyau |, faites éclater deux grilles Aet Bde la pile ( Bétait en haut), et poussez la grille ABobtenue en concaténant Bà droite de A. Cela nécessite cela Aet Bavoir une hauteur égale.
  • Étant donné un trait d'union -, faites éclater deux grilles Aet Bde la pile ( Bétait en haut), et poussez la grille A/Bobtenue en concaténant Bau bas de A. Cela nécessite cela Aet Bavoir une largeur égale.

Il est garanti que pour certains choix de met neffectués pendant le processus d'analyse (qui peuvent être différents pour chaque lettre), la spécification d'entrée décrit correctement un rectangle, qui est laissé sur la pile à la fin.

Production

Votre sortie est une grille rectangulaire de caractères spécifiée par l'entrée. La grille doit être minimale dans le sens où la suppression d'une ligne ou d'une colonne la rendrait non valide. Vous pouvez renvoyer une chaîne séparée par des sauts de ligne (avec ou sans retour à la ligne), un tableau 2D de caractères ou un tableau de chaînes, selon le format le plus pratique.

Notez que vous n'êtes pas obligé de traiter l'entrée exactement comme décrit ci-dessus; la seule chose importante est que votre sortie soit correcte.

Exemple

Considérez la spécification

par-s||e-

Tout d'abord, nous choisissons de pousser un 1×2rectangle de p, et des 1×1rectangles de aet r(la raison en sera claire plus tard). Ensuite, nous les pop aet rrectangles, et pousser leur concaténation verticale

a
r

Ensuite, nous poussons un 1×2rectangle de s, le pop et le rectangle ci-dessus, et poussons leur concaténation horizontale

as
rs

Ensuite, nous pop ce rectangle et le prectangle, et poussons leur concaténation

pas
prs

Enfin, nous poussons un 3×1rectangle de e, le pop et le rectangle ci-dessus, et poussons la concaténation verticale

pas
prs
eee

C'est la sortie du programme, ou au moins l'une des possibilités. Notez que même si

ppas
ppas
pprs
eeee

est également généré par la spécification, ce n'est pas une sortie valide, car de nombreuses lignes et colonnes peuvent être supprimées.

Comme exemple plus subtil, considérez

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

Cette spécification génère le rectangle

comp
iler

qui est une sortie valide. Cependant, il génère également

commp
iiler

ce qui est également valable, car aucune ligne ou colonne ne peut être supprimée sans l'invalider.

Règles

Vous pouvez donner un programme complet ou une fonction. Le nombre d'octets le plus bas gagne et les failles standard sont interdites.

Cas de test supplémentaires

Vous pouvez les utiliser pour tester votre programme.

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
la source
D'où viennent n et m?
seequ
Peut être statique ou doit être une forme d'entrée?
seequ
@Sieg net msont choisis de manière non déterministe. Il est garanti que des valeurs appropriées existent, mais c'est le travail de votre programme de les trouver.
Zgarb
Vous ne définissez pas réellement ce qu'ils sont.
seequ
un|co|p-|yr|i|gh--t-ab|-|le-||-est impossible à valider. Le dernier -a une arité de 2, alors qu'il n'y a qu'un seul élément sur la pile.
orlp

Réponses:

6

K, 123 110 octets

J'ai utilisé une approche similaire à la solution de cardboard_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}/

Ce programme est une série de définitions d'aide suivies d'une fonction tacite qui prend une chaîne comme argument de droite. Reformatage pour la lisibilité et attribution de la fonction finale comme 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]}/;

Exemple d'utilisation:

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

Testé en utilisant Kona, mais il fonctionnera également en oK si vous remplacez le :dans la définition de fpar $- k5 a changé la syntaxe de "cond".

Un point clé est de reconnaître que faire une annexe verticale est la transposition de l'annexe horizontale de la transposition des deux matrices. (Voir la définition v.) Je pense qu'il y a encore de la place pour faire sortir quelques personnages ici et là. Si quelqu'un est intéressé par une explication plus détaillée, je peux en fournir une.

Éditer:

Mise à jour du programme en haut de cette entrée. Version non golfée:

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

Optimisations de longueur notables incluent l'utilisation de « dot appliquer » en aremplaçant le « cond » avec l' indexation de liste f(moins efficace, mais plus court) et le remplacement des termes de la forme a[b;c]dans les a[b]ccas permis par regroupement. Comme je n'utilise plus "cond" ni aucune primitive différente entre k3 et k5, cette version fonctionne maintenant en oK sans modification.

JohnE
la source
Félicitations pour avoir gagné la prime!
Zgarb
Merci! C'était un problème intéressant qui a plutôt bien cédé à K. Il aurait été intéressant de voir des tentatives en J ou APL pour comparaison.
JohnE
4

Prolog, 539 octets

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

Explication

Nous commençons par le prédicat g, qui prend une chaîne, le convertissons en une liste de caractères et appelons le pprédicat (analyse) avec une pile vide comme deuxième argument.

Le prédicat ps'appelle récursivement avec une pile modifiée de manière appropriée (recherchez [H|T]les modèles de déstructuration et de constructeur). Lorsqu'il est appelé dans le cas de base, où la liste d'entrée est vide, pimprime l'élément unique de la pile. Si la pile contient moins ou plus d'un élément à ce stade, cela signifie que nous avons une chaîne d'entrée vide, une mauvaise chaîne d'entrée ou un bogue (avec une chaîne emtpy, le prédicat échoue (Prolog dit No), mais rien n'est imprimé, ce qui est correct, car nous ne devons rien imprimer pour les chaînes vides).

Résoudre

La pile contient une description des rectangles construits, notés S:W:H, où se Strouve une représentation symbolique du rectangle, Wsa largeur et Hsa hauteur (remarque, A:Best le sucre syntaxique pour le :(A,B)tuple avec un foncteur nommé :; il est juste plus court à écrire que d'avoir un tuple avec préfixe).

Les spécifications avec Aet Bsous-rectangle Speuvent être:

  • h(A,B) : concat horizontal de A et B
  • v(A,B) : concat vertical de A et B
  • f(C) : remplir avec C, où C est un code de caractère

Les largeurs et hauteurs des grilles sont des variables de programmation par contraintes: pendant la concaténation verticale (resp. Horizontale), la largeur (resp. Hauteur) des rectangles manipulés est unifiée, tandis que la hauteur résultante (resp. Largeur) est contrainte d'être la somme de la hauteur de chaque sous-grille (resp. la largeur).

L'étape de labellisation à la fin du processus instancie les variables tout en respectant les contraintes, en utilisant les valeurs minimales possibles (c'est une propriété de l'ordre dans lequel les solutions sont essayées).

J'aurais peut-être obtenu une réponse plus courte en utilisant le même raisonnement que celui fait dans d'autres réponses, sans contraintes, mais c'est trop tard maintenant.

Notez également que le domaine par défaut des variables étant défini sur 1..100, il existe une limitation sur les tailles possibles des grilles. La limite supérieure peut être modifiée si nécessaire. Les implications en termes de performances sont que cela pourrait prendre beaucoup de temps pour déterminer qu'une solution particulière n'admet aucune solution. J'ai dit " pourrait " car les contraintes sont susceptibles d'élaguer considérablement la recherche exponentielle. Si vous trouvez une chaîne d'entrée difficile / coûteuse à rejeter, veuillez la partager.

Impression

La partie impression est intéressante car il existe une sorte d' algorithme de lancer de rayons sur la structure: j'itère sur chaque cellule de la grille résultante, de point (1,1)en point (W,H)et appelle le wprédicat pour imprimer le contenu de la grille dans l'arborescence principale, à cet emplacement (bien sûr, une nouvelle ligne est imprimée après le traitement de chaque ligne).

Dans w, les positions sont relatives à la grille actuelle (la grille racine définit les coordonnées absolues).

Lors de l'impression d'une h(A,B)structure au point (X,Y), j'imprime inconditionnellement dans les deux branches:

  • dans la grille Aau point (X,Y), et
  • dans la grille Bau point (H,Y), où Hest Xmoins la largeur de A.

Les branches feuilles de l'arborescence, f(C)enfin, impriment le caractère C, si l'emplacement relatif est à l'intérieur de la grille, ou ne font rien. C'est ainsi que je peux imprimer le contenu de la grille dans le flux de sortie, de haut en bas, de gauche à droite. Aucun tableau réel n'est produit.

Les tests

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.

Test de fonctionnement:

[eclipse] tt.

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe

cccoy
mmply
exify

a

Yes (0.00s cpu)
coredump
la source
+1 No actual arrays are produced.c'est ainsi que cela doit être fait. Trop fort dans ce cas, car la grammaire est si simple et il y a des raccourcis.
edc65
@ edc65 Oui, c'est exagéré. Mais comme il s'agit de codegolf, j'ai essayé de minimiser la taille et la manipulation des tableaux aurait été trop verbeuse.
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]

gest une fonction qui prend une spécification et donne un tableau 2D de caractères. Si vous voulez une version plus conviviale, ajoutez cette ligne pour lui faire prendre une spécification de stdin et imprimer la grille:

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

Cas de 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

Explication

La stratégie est simple: si une grille Gest valide pour une spécification S, la répétition de la colonne la plus à droite de Gdonne également une spécification valide pour S, et il en va de même pour la répétition de la ligne du bas (la preuve en est par induction structurelle activée S). Par conséquent, lorsque nous voulons concaténer deux rectangles, nous pouvons simplement ajouter la dernière colonne / ligne de la plus petite jusqu'à ce qu'ils correspondent en taille (c'est ce que fait la fonction p).

boîte en carton
la source
3

Haskell, 388 367 352 octets

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.(#[])

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

Test avec jolie impression:

> 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

Comment ça marche: la fonction #analyse la chaîne d'entrée dans l'arborescence Cqui est soit une feuille Lcontenant le caractère à imprimer, soit un nœud N. Npeut être a) une jonction côte à côte ( t==2), b) une jonction haut-bas ( t==1) ou c) un carré d'une seule lettre ( t==0). Tous les nœuds ont un champ largeur et hauteur et un enfant gauche et droit. Après l'analyse, pimprime le nœud racine restant en ajustant récursivement la taille (largeur x hauteur) de ses nœuds enfants et en les joignant.

Edit: sortie sous forme de liste de lignes au lieu d'une jolie impression

nimi
la source
1

JavaScript (ES6), 283 295

Modifier Maintenant, cette solution JS (très jouée au golf) est au moins plus courte que la solution Python de référence (assez jouable au golf).

Similaire à cardboard_box, en répétant simplement la colonne la plus à gauche ou la ligne la plus en haut.

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

Non golfé C'est ma première solution non golfée.

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

Tester dans la 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)))

Production

pas
prs
eee

comp
iler

cccoy
mmply
exify

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe
edc65
la source
0

Python 3, 251 octets

Voici la réponse de référence que j'ai promise, j'ai joué un peu plus loin.

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

Il s'agit d'un programme complet qui prend la chaîne de STDIN et l'imprime sur STDOUT. L'approche est la même que celle de cardboard_box: pousser un tableau 1x1 pour un caractère, et dupliquer les lignes si nécessaire pour la concaténation.

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

Explication détaillée

  • Ttranspose une liste donnée de listes. La majorité du travail est effectué par l' zip(*m)échange de lignes en colonnes, le reste convertit simplement le résultat en une liste de listes, car zipretourne un générateur de tuples.
  • E(a,b)renvoie ason premier élément répété suffisamment de fois pour correspondre à la longueur de b. Notez que la multiplication d'une liste par un nombre négatif donne la liste vide, donc si elle best plus courte que a, cela renvoie a.
  • H(a,b)renvoie la concaténation horizontale de aet b, la plus courte étant allongée Esi nécessaire.
  • s est la pile.
  • Dans la forboucle, nous parcourons la chaîne d'entrée et la remplaçons spar une nouvelle valeur: si elle est |(supérieure à z), nous popons deux valeurs et poussons leur H, si elle est -(inférieure à a), nous popons deux valeurs, transposons, alimentons H, transposer à nouveau et pousser le résultat, ou sinon pousser un tableau 1x1 avec la lettre.
  • Enfin, nous imprimons le premier élément de s.
Zgarb
la source