Generieren Sie ein Rechteck aus einer Spezifikation


14

Einführung

Diese Herausforderung ist inspiriert von Grime , meiner 2D-Pattern-Matching-Sprache. Grundsätzlich erhalten Sie eine "Grammatik", die zweidimensionale Gitter von Zeichen beschreibt, und Ihre Aufgabe ist es, ein Gitter gemäß der Grammatik zu generieren. Darüber hinaus sollte das Raster in einem gewissen schwachen Sinne so klein wie möglich sein.

Eingang

Ihre Eingabe ist eine Zeichenfolge, die ASCII-Kleinbuchstaben sowie die Symbole |und enthält -. Der Einfachheit halber enthält die Eingabe keine wiederholten Kleinbuchstaben. Die Zeichenfolge ist eine Spezifikation für eine Klasse von rechteckigen Zeichengittern und wird wie folgt mit einem Stapel von links nach rechts analysiert.

  • Wenn Sie ein Zeichen in Kleinbuchstaben haben c, legen Sie für jedes m×nZeichen ein Raster des Zeichens auf den Stapel .cm, n ≥ 1
  • Bei einem Rohr |, Pop zwei Gitter Aund Baus dem Stapel ( Bwar oben) und schieben das Gitter ABerhält durch Verketten Brechts von A. Dies setzt voraus, dass Aund Bgleich hoch sind.
  • Bei einem Bindestrich -, Pop zwei Gitter Aund Baus dem Stapel ( Bwar oben) und schieben das Gitter A/Berhält durch Verketten Bder an die Unterseite A. Dies setzt voraus, dass Aund Bgleich breit sind.

Es wird garantiert , dass für einige Entscheidungen von mund nbei der Analyse gemacht (die für jeden Buchstaben verschieden sein können), die Eingangsspezifikation korrekt einig Rechteck beschreibt, die auf dem Stapel am Ende übrig bleibt.

Ausgabe

Ihre Ausgabe ist ein rechteckiges Zeichenraster, das von der Eingabe angegeben wird. Das Raster muss in dem Sinne minimal sein, dass es ungültig wird, wenn Zeilen oder Spalten entfernt werden. Sie können eine durch Zeilenumbrüche getrennte Zeichenfolge (mit oder ohne abschließende Zeilenumbrüche), ein 2D-Array von Zeichen oder ein Array von Zeichenfolgen zurückgeben, je nachdem, welches Format das bequemste ist.

Beachten Sie, dass Sie die Eingabe nicht genau wie oben beschrieben verarbeiten müssen. Wichtig ist nur, dass Ihre Ausgabe korrekt ist.

Beispiel

Beachten Sie die Spezifikation

par-s||e-

Zuerst wählen wir ein 1×2Rechteck aus pund 1×1Rechtecke aus aund r(der Grund dafür wird später klar). Dann knallen wir die aund rRechtecken, und ihre vertikale Verkettung schieben

a
r

Als nächstes verschieben wir ein 1×2Rechteck von s, platzieren es und das obige Rechteck und verschieben ihre horizontale Verkettung

as
rs

Dann platzieren wir das Rechteck und das pRechteck und verschieben ihre Verkettung

pas
prs

Schließlich verschieben wir ein 3×1Rechteck von e, platzieren es und das obige Rechteck und verschieben die vertikale Verkettung

pas
prs
eee

Dies ist die Ausgabe des Programms oder mindestens eine der Möglichkeiten. Beachten Sie das, obwohl

ppas
ppas
pprs
eeee

Wird auch von der Spezifikation generiert, handelt es sich nicht um eine gültige Ausgabe, da viele der Zeilen und Spalten entfernt werden könnten.

Betrachten Sie als subtileres Beispiel

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

Diese Angabe erzeugt das Rechteck

comp
iler

Das ist eine gültige Ausgabe. Es erzeugt jedoch auch

commp
iiler

Dies gilt auch, da keine einzelne Zeile oder Spalte entfernt werden kann, ohne sie ungültig zu machen.

Regeln

Sie können ein vollständiges Programm oder eine Funktion angeben. Die niedrigste Byteanzahl gewinnt, und Standardlücken sind nicht zulässig.

Zusätzliche Testfälle

Mit diesen können Sie Ihr Programm testen.

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

Woher kommen n und m?
Siehe auch

Kann statisch sein oder muss eine Form von Eingabe sein?
Siehe auch

@Sieg nund mwerden nicht deterministisch gewählt. Es ist garantiert, dass geeignete Werte für sie existieren, aber es ist Aufgabe Ihres Programms, sie zu finden.
Zgarb,

Sie definieren nicht wirklich, was sie sind.
Siehe auch

un|co|p-|yr|i|gh--t-ab|-|le-||-ist unmöglich, gültig zu sein. Der letzte -hat eine Arität von 2, während sich nur 1 Element auf dem Stapel befindet.
Orlp

Antworten:


6

K, 123-110 Bytes

Ich habe einen ähnlichen Ansatz für die Lösung von cardboard_box gewählt.

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

Dieses Programm besteht aus einer Reihe von Hilfsdefinitionen, gefolgt von einer impliziten Funktion, die einen String als rechtes Argument verwendet. Neuformatierung zur besseren Lesbarkeit und Zuweisung der endgültigen Funktion als 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]}/;

Anwendungsbeispiel:

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

Getestet mit Kona, funktioniert aber auch in OK, wenn Sie das :in der Definition von ersetzenf durch a $- k5 geänderte Syntax von "cond" .

Ein wichtiger Punkt ist das Erkennen, dass ein vertikales Anhängen die Transponierung des horizontalen Anhängens der Transponierung beider Matrizen ist. (Siehe Definitionv .) Ich denke, es gibt immer noch Raum, um hier und da ein paar Zeichen auszudrücken. Wenn jemand an einer detaillierteren Erklärung interessiert ist, kann ich eine liefern.

bearbeiten:

Das Programm oben in diesem Eintrag wurde aktualisiert. Ungolfed-Version:

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

Zu den bemerkenswerten Längenoptimierungen gehört die Verwendung von "Punkt anwenden" in a, das Ersetzen von "Kond" durch das Indizieren in Listen f(weniger effizient, aber kürzer) und das Ersetzen von Begriffen des Formulars a[b;c]in, a[b]csofern dies durch Gruppierung zulässig ist. Da ich "cond" oder andere Primitive, die sich von k3 und k5 unterscheiden, nicht mehr verwende, funktioniert diese Version jetzt in OK ohne Änderungen.


Herzlichen Glückwunsch zum Gewinn der Prämie!
Zgarb

Vielen Dank! Es war ein interessantes Problem, das sich für K recht gut erwies. Es wäre interessant gewesen, Versuche in J oder APL zum Vergleich zu sehen.
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]).

Erläuterung

Wir beginnen mit einem Prädikat g, das eine Zeichenfolge annimmt, diese als Liste von Zeichen konvertiert und die aufruftp Prädikat (parse) mit einem leeren Stapel als zweites Argument aufruft.

Das Prädikat pruft sich selbst rekursiv mit einem entsprechend geänderten Stack auf (suchen Sie nach [H|T]Destrukturierungs- und Konstruktormustern). Beim Aufruf im Basisfall, in dem die Eingabeliste leer ist, wird pdas eindeutige Element des Stapels gedruckt. Wenn der Stack zu diesem Zeitpunkt weniger oder mehr als ein Element enthält, bedeutet dies, dass eine leere Eingabezeichenfolge, eine ungültige Eingabezeichenfolge oder ein Fehler vorliegt (bei einer leeren Zeichenfolge schlägt das Prädikat fehl (sagt Prolog)No ), es wird jedoch nichts gedruckt). was ok ist, da wir für leere Strings nichts drucken sollten).

Lösen

Der Stapel enthält eine Beschreibung der konstruierten Rechtecke, bezeichnet S:W:Hmit Seiner symbolischen Darstellung des Rechtecks, Wseiner Breite und Hseiner Höhe (Anmerkung: A:BSyntaxzucker für das :(A,B)Tupel mit einem Funktor namens: ; es ist nur kürzer zu schreiben als ein Tupel) mit Präfixnotation).

Mit Aund Bunter Rechteckspezifikationen Skann Folgendes angegeben werden:

  • h(A,B) : Horizontalkonzentrat von A und B
  • v(A,B) : vertikales Concat von A und B
  • f(C) : mit C füllen, wobei C ein Zeichencode ist

Breiten und Höhen von Gittern sind Variablen zur Programmierung von Abhängigkeiten: Während der vertikalen (bzw. horizontalen) Verkettung wird die Breite (bzw. Höhe) der manipulierten Rechtecke vereinheitlicht, während die resultierende Höhe (bzw. Breite) auf die Summe von beschränkt wird Höhe (bzw. Breite) jedes Subgrids.

Der Beschriftungsschritt am Ende des Prozesses instanziiert Variablen unter Berücksichtigung von Einschränkungen unter Verwendung der minimal möglichen Werte (dies ist eine Eigenschaft der Reihenfolge, in der Lösungen ausprobiert werden).

Ich hätte vielleicht eine kürzere Antwort erhalten, wenn ich die gleiche Neuformulierung verwendet hätte wie bei anderen Antworten, ohne Einschränkungen, aber das ist jetzt zu spät.

Da die Standarddomäne für Variablen auf festgelegt ist 1..100, gibt es eine Einschränkung hinsichtlich der möglichen Rastergrößen. Die Obergrenze kann bei Bedarf geändert werden. Die Auswirkungen auf die Leistung davon sind , dass es könnte eine Menge Zeit in Anspruch nehmen , um festzustellen , dass eine bestimmte Lösung keine Lösung gibt. Ich sagte " könnte ", weil Einschränkungen wahrscheinlich die exponentielle Suche drastisch beschneiden. Wenn Sie eine Eingabezeichenfolge finden, deren Zurückweisung schwierig / kostspielig ist, teilen Sie diese bitte mit.

Drucken

Der Druckteil ist interessant, weil es eine Art Raycasting- Algorithmus für die Struktur gibt: Ich iteriere über jede Zelle des resultierenden Gitters von Punkt (1,1)zu Punkt (W,H)und rufe das wPrädikat auf, um den Inhalt des Gitters im Hauptbaum zu drucken Diese Position (natürlich wird nach der Verarbeitung jeder Zeile eine neue Zeile gedruckt).

In wsind die Positionen relativ zum aktuellen Raster (das Wurzelraster definiert absolute Koordinaten).

Beim Drucken einer h(A,B)Struktur an einem Punkt (X,Y)drucke ich bedingungslos in beiden Zweigen:

  • im Raster Aam Punkt (X,Y)und
  • in grid Bam Punkt (H,Y), wo Hist Xminus der Breite A.

Die Blattäste des Gitterbaums geben f(C)schließlich entweder das Zeichen aus C, wenn sich die relative Position innerhalb des Gitters befindet, oder tun nichts. Auf diese Weise kann ich den Inhalt des Rasters von oben nach unten und von links nach rechts in den Ausgabestream drucken. Es werden keine tatsächlichen Arrays erzeugt.

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.

Lauftest:

[eclipse] tt.

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe

cccoy
mmply
exify

a

Yes (0.00s cpu)

+1 No actual arrays are produced.So sollte es gemacht werden. Overkill in diesem Fall, da die Grammatik so einfach ist und es Verknüpfungen gibt.
edc65

@ edc65 Ja, es ist übertrieben. Da es sich jedoch um Codegolf handelt, habe ich versucht, die Größe zu minimieren, und das Manipulieren von Arrays wäre zu ausführlich gewesen.
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]

gist eine Funktion, die eine Spezifikation annimmt und ein 2D-Array von Zeichen liefert. Wenn Sie eine benutzerfreundlichere Version wünschen, fügen Sie diese Zeile hinzu, um eine Spezifikation aus stdin zu übernehmen und das Raster auszudrucken:

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

Testfälle

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

Erläuterung

Die Strategie ist einfach: Wenn ein Raster Gfür eine Spezifikation gültig ist S, gibt das Wiederholen der rechten Spalte von Gauch eine gültige Spezifikation für Sund das Gleiche gilt für das Wiederholen der unteren Zeile (der Beweis hierfür erfolgt durch strukturelle Induktion von S). Wenn wir also zwei Rechtecke verketten möchten, können wir einfach die letzte Spalte / Zeile der kleineren anhängen, bis sie in der Größe übereinstimmen (das ist, was die Funktion p tut).


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

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

Testlauf mit schönem Druck:

> 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

Funktionsweise: Die Funktion #analysiert die Eingabezeichenfolge in der Baumstruktur, Cdie entweder ein Blatt Lmit dem zu druckenden Zeichen oder einen Knoten enthält N. Nkann a) ein Side-by-Side-Join ( t==2) sein, b) ein Top-Bottom-Join (t==1 ) oder c) ein einzelnes Buchstabenquadrat ( t==0) sein. Alle Knoten haben ein Feld für Breite und Höhe sowie ein untergeordnetes Element für links und rechts. Druckt nach dem Parsen pden verbleibenden Stammknoten, indem rekursiv die Größe (Breite x Höhe) der untergeordneten Knoten angepasst und diese verbunden werden.

Bearbeiten: Ausgabe als Zeilenliste statt hübsches Drucken


1

JavaScript (ES6), 283 295

Bearbeiten Nun ist diese (stark golfene) JS-Lösung mindestens kürzer als die Referenz (ziemlich golfene) Python-Lösung.

Ähnlich wie bei cardboard_box wiederholen Sie einfach die Spalte ganz links oder die Zeile ganz oben.

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 Dies ist meine erste ungolfed Lösung.

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 In der Firefox / FireBug-Konsole

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

Ausgabe

pas
prs
eee

comp
iler

cccoy
mmply
exify

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe

0

Python 3, 251 Bytes

Hier ist die Antwort, die ich versprochen habe und die ein bisschen weiter fortgeschritten ist.

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

Dies ist ein vollständiges Programm, das die Zeichenfolge von STDIN übernimmt und zu STDOUT druckt. Der Ansatz ist der gleiche wie bei cardboard_box: Verschieben Sie ein 1x1-Array für ein Zeichen und duplizieren Sie die Zeilen, falls dies zur Verkettung erforderlich ist.

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

Ausführliche Erklärung

  • Ttransponiert eine gegebene Liste von Listen. Der Großteil der Arbeit wird durch zip(*m)das Vertauschen von Zeilen in Spalten erledigt , der Rest konvertiert nur das Ergebnis in eine Liste von Listen, da zipein Tupelgenerator zurückgegeben wird.
  • E(a,b)Gibt zurück, awenn das erste Element so oft wiederholt wird, dass es der Länge von entspricht b. Beachten Sie, dass das Multiplizieren einer Liste mit einer negativen Zahl die leere Liste ergibt. Wenn diese balso kürzer als ist a, wird dies zurückgegeben a.
  • H(a,b)Gibt die horizontale Verkettung von aund zurück b, wobei die kürzere Ebei Bedarf verlängert wird .
  • s ist der Stapel.
  • In der forSchleife iterieren wir über die Eingabezeichenfolge und ersetzen sie sdurch einen neuen Wert: Wenn es |(größer als z) ist, fügen wir zwei Werte hinzu und verschieben sie H. Wenn es -(kleiner als a) ist, fügen wir zwei Werte hinzu, transponieren, füttern H, transponieren Sie erneut und drücken Sie das Ergebnis, andernfalls drücken Sie ein 1x1-Array mit dem Buchstaben.
  • Schließlich drucken wir das erste Element von s.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.