Machen Sie den Stretchy Snakes Kiss

57

Eine dehnbare Schlange sieht ungefähr so ​​aus:

<||=|||:)~

Jede separate Folge von vertikalen Balken ( |) in einer dehnbaren Schlange, die als dehnbarer Abschnitt bezeichnet wird, kann einzeln auf das Doppelte ihrer Breite ausgedehnt werden und wird mit abwechselnden Schrägstrichen ( /, \) gezeichnet , sobald sie ausgedehnt sind.

Die bestimmte Schlange oben hat zwei derartig dehnbare Teile, was vier mögliche Posen ergibt:

<||=|||:)~

</\/\=|||:)~

<||=/\/\/\:)~

</\/\=/\/\/\:)~

Die allgemeine Form einer dehnbaren Schlange in ihrer am wenigsten gedehnten Haltung wird durch diesen regulären Ausdruck definiert :

<(\|+=)*\|+:\)~

Was kann in Worten ausgedrückt werden als:

<, gefolgt von einer beliebigen Anzahl von Sequenzen von |'s, verbunden mit =Zeichen, gefolgt von :)~.

Also <|:)~und <||:)~und <|=|:)~und <|=|=||=|||||=||:)~sind dehnbare Schlangen, aber <=:)~und <=|:)~und <||=:)~und <|==||:)~sind es nicht.

Dehnbare Schlangen können auch nach links statt nach rechts schauen, z ~(:|||=||>. Die Formen sind die gleichen, nur gespiegelt.

Herausforderung

Schreiben Sie ein Programm, das eine einzelne Zeile mit zwei sich gegenüberliegenden dehnbaren Schlangen mit einer gewissen Anzahl von Leerzeichen dazwischen aufnimmt. Beide Schlangen befinden sich in ihrer am wenigsten gedehnten Position (alle vertikalen Balken, keine Schrägstriche). Die Zeichenfolge beginnt mit dem Schwanz der nach rechts zeigenden Schlange und endet mit dem Schwanz der nach links zeigenden Schlange (Sie können optional davon ausgehen, dass es auch eine nachgestellte Newline gibt).

Hier ist zum Beispiel eine mögliche Eingabe mit fünf Leerzeichen zwischen den Schlangen:

<|=||:)~.....~(:||||>

Ich verwende Punkte ( .) anstelle von Leerzeichen, um die Übersichtlichkeit zu verbessern.

Nullabstände zwischen Schlangen sind ebenfalls gültige Eingaben:

<|=||:)~~(:||||>

Wir sagen, die Schlangen küssen sich, wenn sich ihre Zungen so berühren.

Ihr Programm muss eine Kombination der dehnbaren Teile beider Schlangen so erweitern, dass die Schlangen die geringstmögliche Anzahl von Zwischenräumen zwischen sich haben (ohne sich zu überlappen), dh, dass die Schlangen dem Küssen so nahe wie möglich kommen .

Die beiden Schwänze der Schlangen sind fixiert, aber ihre Köpfe und Körper können sich bewegen - rechts für die nach rechts gerichtete Schlange, links für die nach links gerichtete Schlange - je nachdem, welche dehnbaren Teile gedehnt wurden.

Die Ausgabe Ihres Programms ist die einzeilige Zeichenfolge (plus optionaler abschließender Zeilenumbruch), die die Schlangen so nah wie möglich am Küssen zeigt, wobei abwechselnd Schrägstriche anstelle von vertikalen Balken für gestreckte Teile gezeichnet werden, die verlängert wurden.


Die Ausgabe für <|=||:)~.....~(:||||>(von oben) wäre beispielsweise:

</\=||:)~~(:/\/\/\/\>

Dies ist die einzige Lösung, da sich bei jeder anderen Kombination der gedehnten Teile die Schlangen entweder überlappen oder weiter vom Küssen entfernt sind.


Wenn mehrere Lösungen möglich sind, kann es sich bei der Ausgabe um eine beliebige handeln.

Zum Beispiel, wenn die Eingabe wäre

<|=||:)~.....~(:|||=|>

die Ausgabe könnte sein

<|=/\/\:)~~(:/\/\/\=|>

oder

</\=||:)~~(:/\/\/\=/\>

Denken Sie daran, dass es nicht immer möglich ist, die Schlangen zum Küssen zu bringen, aber Sie müssen sie trotzdem so nah wie möglich bringen.

Zum Beispiel, wenn die Eingabe wäre

<||=||||:)~...~(:||>

die Ausgabe könnte sein

</\/\=||||:)~.~(:||>

oder

<||=||||:)~.~(:/\/\>

Wenn sich die Schlangen bereits küssen, entspricht die Ausgabe der Eingabe. z.B

<|=||:)~~(:||||>

Im Allgemeinen ist die Ausgabe dieselbe wie die Eingabe, wenn sich die Schlangen durch die Ausdehnung eines dehnbaren Abschnitts überlappen würden. z.B

<|||=|||:)~..~(:||||=|||||=||||||>

Anmerkungen

  • Übernimmt wie gewohnt die Eingabe von stdin oder der Befehlszeile oder schreibt eine Funktion, die eine Zeichenfolge akzeptiert. Ausgabe drucken oder zurücksenden.
  • Sie können Punkte ( .) in der Eingabe und Ausgabe anstelle von Leerzeichen ( ) verwenden, wenn Sie dies vorziehen.
  • Es ist nur wichtig, dass sich Schrägstriche in der Reihenfolge der vertikalen Balken abwechseln, die sie ersetzt haben. Ihre Reihenfolge in der Schlange insgesamt oder ob ein vorwärts oder rückwärts gerichteter Schrägstrich zuerst kommt, spielt keine Rolle.
  • Dehnbare Teile können sich nicht teilweise erstrecken - es ist genau doppelt so lang oder überhaupt nicht.

Wertung

Das ist Code-Golf . Die kürzeste Übermittlung in Bytes gewinnt. Tiebreaker ist frühere Antwort.

Calvins Hobbys
quelle
17
Snex Education 101 - Wie man richtig küsst
Optimierer
45
"Wir sagen, die Schlangen küssen sich, wenn sich ihre Zungen so berühren." Was lese ich gerade ...
Fatalize
8
Schlangen machen also nur Französisch?
Optimierer
3
@PeterTaylor Nun, "gespiegelt", nicht "umgekehrt" (sonst >würde es auch nicht <dasselbe für (und werden )), aber er sagt auch "Es ist nur wichtig, dass sich Schrägstriche in der Reihenfolge der vertikalen Balken abwechseln, die sie ersetzt haben Schlange auf freiem Fuß oder ob ein vorwärts oder rückwärts gerichteter Schrägstrich zuerst kommt, spielt keine Rolle. "
Martin Ender
7
@qwr Imagination.
Calvins Hobbys

Antworten:

9

CJam, 87 71 70 68 Bytes

l:L"|"f&Qa%_,Y\m*\f{.{_,"/\\"*?}L'|%.\s" /"1$fe=:-\a+}${0a>}=~S%\S**

Probieren Sie es online im CJam-Interpreter aus .

Wie es funktioniert

l:L        e# Read a line from STDIN and save it in L.
"|"f&      e# Intersect each character with the string "|".
           e# This pushes either "|" or "".
Qa%        e# Split the resulting array at runs of "".
_,         e# Compute the length of the resulting array (A).
           e# This yield K, the number of stretchy parts.
Y\m*       e# Push the array of all vectores in {0,1}^K.
\f{        e# For each vector V in {0,1}^K, push V and A; then:
  .{       e#   For each C in V and the corresponding P in A:
    _,     e#     Compute the length of the stretchy part P.
    "/\\"* e#     Repeat "/\" that many times.
    ?      e#     If C, select P; else, select "/\"*length(P).
  }        e#   This modifies A.
  L'|%     e#   Split L at runs of vertical lines.
  .\s      e#   Interleave the chunks of L and the modified A. Sringify.
           e#   In each iteration, this constructs a different modification of L,
           e#   with some stretched out stretchy parts.
  " /"1$   e#   Push " /" and a copy of the modified L.
  fe=      e#   Calculate the number of spaces and slashes in the modifed L.
  :-       e#   Subtract the number of occurrences.
  \a+      e#   Construct the array [difference modified-L].
}          e#
$          e# Sort the array (by final number of spaces).
{0a>}=     e# Find the first element greater than [0].
           e# This skips over too far stretched snakes, where the number of
           e# slashes is less than the number of spaces.
~          e# Dump the difference (D) and modified L on the stack.
S%         e# Split L at runs of spaces.
\S*        e# Construct a string of D spaces.
*          e# Join the split L, delimiting by D spaces.
Dennis
quelle
19

Retina , 209 107 99 97 92 Bytes

.(?=(.+)(?<=(?=<((\|+|(?<-5>\|(?=\1())?)+)[^|]+)+$(?(5)!)).+( )+\S+))\4
/ \
+` (.*~|~.*) 
$1

Zu Zählzwecken wird jede Zeile in einer separaten Datei abgelegt. Sie können den Code jedoch mit dem -sFlag aus einer einzelnen Datei ausführen .

Bringen Sie die besten Eigenschaften von .NET Regex und Retina zusammen: Balancing Groups, Lookbehinds mit beliebiger Länge und wiederholte Substitution von Regex.

Im Wesentlichen codiert der lange reguläre Ausdruck eine gültige Lösung und der Backtracker der regulären Ausdrucksmaschine findet eine der für mich optimalen.

Erläuterung

Lassen Sie uns zunächst überlegen, wie wir mit einer regulären Ausdrucksweise eine gültige Lösung finden können (die nicht unbedingt die richtige Ausgabe liefert). Wir können die Bilanzgruppen von .NET verwenden , um die dehnbaren Teile zu zählen. Betrachten Sie den folgenden einfacheren regulären Ausdruck:

\S+( )+.+(?<=(?(1)!)^([^|]+(\|+|(?<-1>\|)*))+>)

Wir können das erkennen.

\S+( )+.+

Dies entspricht der gesamten Zeichenfolge, wobei 1für jedes Feld in der Eingabe ein Capture auf den Gruppenstapel verschoben wird. Wir werden diesen Stapel verwenden, um sicherzustellen, dass die dehnbaren Teile genau den in diesen Gruppen erfassten Raum ausfüllen.

Weiter ist ein Lookbehind. Der Haken ist, dass Lookbehinds in .NET von rechts nach links abgeglichen werden (so sollten Sie sie also lesen). Dies gibt uns die Möglichkeit, die Zeichenfolge ein zweites Mal zu durchlaufen und herauszufinden, ob es eine Teilmenge von dehnbaren Teilen gibt, die sich aus der Anzahl der übereinstimmenden Leerzeichen zusammensetzt. Blick hinter die Kulissen von rechts nach links:

>

Dies soll nur sicherstellen, dass wir tatsächlich am Ende der Saite (dem Schwanz der Schlange) beginnen.

(
  [^|]+
  (
    \|+
  |
    (?<-1>\|)+
  )
)+

Für jedes dehnbare Teil entspricht dies entweder nur dem gesamten Teil, ohne etwas zu tun ( \|+), oder es entspricht dem gesamten Teil, während das Abspringen vom Stapel erfolgt 1( (?<-1>\|)*). Diese Abwechslung stellt sicher, dass wir einen dehnbaren Teil nur vollständig ausdehnen oder unverändert lassen können und keine Dinge wie erhalten |/\|. Dann fahren wir mit dem nächsten dehnbaren Teil fort [^|]+.

(?(1)!)^

Schließlich stellen wir sicher, dass wir die gesamte Zeichenfolge (beide Schlangen) durchlaufen haben und der Stapel 1vollständig leer ist. Das heißt, wir haben eine Teilmenge eines dehnbaren Teils gefunden, die genau der Anzahl der zuvor erfassten Räume entspricht.

Der Backtracker durchläuft die Zeichenfolge und probiert alle Kombinationen unveränderter und erweiterter Teile aus, bis das Teilmengenproblem gelöst ist. Wenn eine solche Untermenge nicht existiert, schlägt der Lookbehind fehl. Dies führt dazu, dass der Backtracker zum \S+( )+.+Teil zurückkehrt und versucht, ein Feld weniger zu erfassen ( )+(was .+stattdessen nur abgedeckt wird ). Aufgrund der Gier von +versuchen wir daher, so viele Räume wie möglich zu füllen.

Sie können die Gültigkeit dieses Ansatzes mit dieser leicht geänderten Substitution überprüfen:

\S+(( )+).+(?<=(?(2)!)^([^|]+(\|+|(?<-2>\|)*))+>)
=$1=

So erhalten Sie eine Zeichenfolge =spaces=mit genau der Anzahl von Leerzeichen, die mit den angegebenen Schlangen gefüllt werden können.

Ich musste ein paar weitere Tricks hinzufügen, um die korrekten |s tatsächlich zu erweitern . Grundsätzlich möchte ich alle |s ersetzen, die mit dem (?<-1>\|)+Zweig abgeglichen wurden . Die Idee ist, ein einzelnes Zeichen zu finden, den Löser in einen Lookaround zu versetzen und ein Flag zu setzen, wenn das Match zufällig in diesem Zweig liegt. Wenn dieses Flag nicht gesetzt war, wird die Übereinstimmung am Ende ungültig, um das Ersetzen anderer Zeichen zu vermeiden.

Dazu verwenden wir eine Reihe verschachtelter Lookarounds. Auch hier werden die Lookbehinds von .NET mit variabler Länge von rechts nach links abgeglichen. Wenn wir also Lookaheads und Lookbehinds verschachteln, können wir die Regex-Engine die Zeichenfolge mehrere Male durchlaufen lassen. Aus Golfgründen wird der Löser in meiner tatsächlichen Lösung umgekehrt (beginnend am Ende, indem die Zwischenräume von rechts nach links aufgenommen und dann die Teilmengensumme von links nach rechts aufgelöst werden), aber ansonsten ist die Struktur des Lösers genau dieselbe . Lassen Sie uns den gesamten regulären Ausdruck analysieren:

.(?=(.+)...)

Wir passen ein einzelnes Zeichen an, erfassen dann den Rest der Zeichenfolge und bewegen den Cursor an das Ende der Zeichenfolge. Wir werden diese Gruppe 1später verwenden, um im Löser zu überprüfen, ob wir uns an der Position des Spiels befinden.

(?<=....+( )+\S+)

Dies ist wie der erste Teil des oben beschriebenen einfachen Lösers, mit der Ausnahme, dass wir die Leerzeichen von rechts nach links aufnehmen. Das Zurückverfolgen der Anzahl der Leerzeichen funktioniert genauso wie zuvor, außer dass wir jetzt group verwenden 5.

(?=<((\|+|(?<-5>\|(?=\1())?)+)[^|]+)+$(?(5)!))

Dies ist das Gleiche wie zuvor, mit der Ausnahme, dass wir von links nach rechts gehen und jedes Mal, wenn wir einen |Zweig in der expandierenden Verzweigung zuordnen, prüfen wir, ob dieser mit dem richtigen übereinstimmt

(?=\1())?

Dies ist ein optionaler Lookahead. Es wird erneut versucht, eine Übereinstimmung mit der Gruppe 1herzustellen (was hier nur möglich ist, wenn wir direkt nach dem übereinstimmenden Zeichen sind). In diesem Fall wird eine leere Zeichenfolge in einer Gruppe erfasst 4, die angibt, dass wir das aktuelle Zeichen in einer gefunden haben der erweiterten Bits. Wenn \1keine Übereinstimmung vorliegt, 4wird nichts erfasst. ?Dadurch wird sichergestellt, dass der fehlerhafte Lookahead den Solver überhaupt nicht beeinträchtigt.

Schließlich überprüfen wir nach Abschluss der Lösung nur, \4ob dieser Lookahead verwendet wurde. In diesem Fall möchten wir das aktuelle Zeichen durch ersetzen /\.

Eine Schwierigkeit bleibt bestehen: die richtige Anzahl von Leerzeichen entfernen. Der kürzeste Weg, dies zu tun, den ich bisher gefunden habe, besteht darin, ein Leerzeichen zusammen mit dem einzufügen /\und dann in einem separaten Schritt ein Leerzeichen zwischen den Zungen für jedes dieser Markierungsfelder zu entfernen:

+` (.*~|~.*) 
$1
Martin Ender
quelle
6

Ruby 191 187 186 170 162

->t{s=r=t.size
i=m=t[o=/ +/].size
(0...2**t.scan(y=/\|+/).size).map{|n|q=-1
x=t.gsub(y){|r|n[q+=1]<1?r:'\/'*r.size}
d=i+s-x.size
d<0||d<m&&r=x.gsub(o,' '*m=d)}
r}

Dies ist eine Funktion, die eine Zeichenfolge als Parameter verwendet und eine Zeichenfolge zurückgibt.

Online-Tests: http://ideone.com/uhdfXt

Hier ist die lesbare Version:

# enumerates the possible states for any string containing snakes
COMBINATIONS =-> snake {
  expandable_fragments = snake.scan /(\|+)/

  (0...2**(expandable_fragments.size)).map{ |i|
    x=-1
    snake.gsub(/\|+/){|r| i[x+=1]>0 ? '\/'*r.size : r}
  }
}

# finds the configuration in which snakes are closest to each other
KISS=
-> input {
  result = input
  s = input.size
  initial_distance = min_distance = input[/ +/].size

  COMBINATIONS[input].map{|c|
    distance = initial_distance + s - c.size
    if distance > -1 && distance < min_distance
      min_distance = distance
      result = c.gsub(/ +/,' '*distance)
    end
  }

  result
}

In der Golfversion entspricht die KISSHauptfunktion der obigen Funktion, und die COMBINATIONSFunktion wurde eingezeichnet.

Cristian Lupascu
quelle
Schlägt bei der Eingabe fehl <|=||:)~~(:||||>, was in der Spezifikation als gültige Eingabe angegeben ist.
Value Ink
6

Python, 205 Bytes

from itertools import*
f=lambda s:min([c.replace(".","",c.count("X"))for c in map("".join,product(*map({"|":"|X"}.get,s,s)))if{c.count("X")>c.count("."),"|X"in c,"X|"in c}=={0}],key=len).replace("X","/\\")

Ein einziges Lambda sieht gut aus, aber ich bin mir fast sicher, dass dies nicht der beste Weg ist. Aber ich poste das, weil alles, was ich bisher habe, halb anständig aussieht.

Dies ist eine einfache rohe Gewalt über alle möglichen Ersetzungen von |mit /\, wobei die ungültigen Konfigurationen herausgefiltert werden. Die einzige saubere Bit Ich glaube , ist , dass wir tatsächlich jede nicht ersetzen |mit /\direkt - wir zuerst ersetzen |mit Xund fallen .für jeden Ersatz aus der Mitte nehmen Sie die minimale Länge Zeichenfolge über alle gültigen Strings, dann ersetzen die Xs mit /\.

Ich habe ein paar andere Ansätze ausprobiert, darunter auch rekursive, aber sie endeten ziemlich chaotisch. Ich habe auch gelernt, dass sich re.splitderzeit keine leeren Zeichenfolgen teilen, was bedauerlich war, da eine meiner Ideen darin bestand, an \bWortgrenzen zu spalten .

Sp3000
quelle
5

Mathematica, 381 Bytes

StringReplace[MapAt[StringReplace[#,"|"->"/\\"]&,StringSplit[#<>"="<>#2,"="],#3]~StringRiffle~"=",")="->")~"<>If[#4>0,"."~StringRepeat~#4,""]<>"~"]&[#1,#3,Sequence@@Function[{l,s},{#,#2-Total@Extract[l,#]}&[Flatten[l~Position~#~Take~#2&@@@Tally@#&@@Select[Subsets@l,Total@#<=s&]~MaximalBy~Total,1],s]][StringLength/@StringCases[#1<>#3,"|"..],StringLength@#2]]&@@#~StringSplit~"~"&

Reine Funktion, die den String als Argument verwendet. Erwartet .eher als zwischen den Schlangen.

Ich hätte nicht gedacht, dass es so schlimm werden würde ... Hier ist, was ich hatte, bevor ich es zusammengeschlagen und alles hinzugefügt habe.

f[lhs_, rhs_, 
  spaces_] := {StringLength /@ StringCases[lhs <> rhs, "|" ..], 
  StringLength@spaces}

g[barLens_, 
   spaceLen_] := {#, #2 - Total@Extract[barLens, #]} & @@ {Flatten[
     Take[Position[barLens, #], #2] & @@@ 
      Tally[First[
        MaximalBy[Select[Subsets[barLens], Total@# <= spaceLen &], 
         Total]]], 1], spaceLen};

h[lhs_, rhs_, partspec_, newSpaceLen_] := 
 StringReplace[
  StringRiffle[
   MapAt[StringReplace[#, "|" -> "/\\"] &, 
    StringSplit[lhs <> "=" <> rhs, "="], partspec], "="], 
  ")=" -> ")~" <> 
    If[newSpaceLen > 0, StringRepeat[".", newSpaceLen], ""] <> "~"]

 h[#1, #3, Sequence @@ g @@ f[#1, #3, #2]] & @@ 
     StringSplit[#, "~"] &

Hier ist ein Beispiel mit Erklärung:

Input: "<|=||:)~.....~(:||||>"
@Call StringSplit[#, "~"] &, yielding  {"<|=||:)", ".....", "(:||||>"}
@@Apply h[#1, #3, Sequence @@ g @@ f[#1, #3, #2]] &, but first
Set arguments: h["<|=||:)", "(:||||>", Sequence @@ g @@ f["<|=||:)", "(:||||>", "....."]]
@Call f, yielding {{1, 2, 4}, 5} = {# of bars in each segment, # of spaces}
@@Apply g, let's trace from the interior:
Subsets[barLens] = all subsets of {1, 2, 4}
Select those subsets whose sum is less than # of spaces {{},{1},{2},{4},{1,2},{1,4}}
MaximalBy Total, yielding a list of all subsets whose sum is maximal {{1, 4}}
First of these subsets, can be any of them {1, 4}
Tally the subset, yielding frequencies of each {{1, 1}, {4, 1}}
@@@Apply Take[Position[barLens, #], #2] & at the first level, yielding
    {Take[Position[{1, 2, 4}, 1], 1], Take[Position[{1, 2, 4}, 4, 1]]}
    which takes the first 1 positions of 1 and the first 1 positions of 4, yielding
    {{{1}},{{3}}}
Flatten at the first level, yielding {{1}, {3}}
Create a list {{{1}, {3}}, 5}
@@Apply {#, #2 - Total@Extract[barLens, #]} &, inserting arguments:
    {{{1}, {3}}, 5 - Total@Extract[{1, 2, 4}, {{1}, {3}}]} = {{{1}, {3}}, 0}
    where the second element becomes the # of spaces left over.
Done with g, it returned {{{1}, {3}}, 0}
@@Apply Sequence, splicing the return of g into h, yielding the
@Call, h["<|=||:)", "(:||||>", {{1}, {3}}, 0]; let's start from the interior
StringSplit the concatenated "<|=||:)=(:||||>" with delimiter "=", {"<|","||:)","(:||||>"}
MapAt the part specification {{1}, {3}} and StringReplace at those indices any | with /\
    yielding {"</\","||:)","(:/\/\/\/\>"}
StringRiffle together, inserting back the delimiter "=", yielding "</\=||:)=(:/\/\/\/\>"
StringReplace ")=" with ")~", concat the new number of spaces, concat "~"
Yields "</\=||:)~~(:/\/\/\/\>", done.
jcai
quelle
Einfach auf 355 reduziert, indem a=StringReplace;b=StringSplit;c=StringLength;d=Total;die folgenden Elemente an einer anderen Stelle im Inneren verwendet und ersetzt werden:a=StringReplace;b=StringSplit;c=StringLength;d=Total;a[MapAt[a[#,"|"->"/\\"]&,b[#<>"="<>#2,"="],#3]~StringRiffle~"=",")="->")~"<>If[#4>0,"."~StringRepeat~#4,""]<>"~"]&[#1,#3,Sequence@@Function[{l,s},{#,#2-d@Extract[l,#]}&[Flatten[l~Position~#~Take~#2&@@@Tally@#&@@Select[Subsets@l,d@#<=s&]~MaximalBy~d,1],s]][c/@StringCases[#1<>#3,"|"..],c@#2]]&@@#~b~"~"&
Alex Meiburg,
3

Prolog (ECLiPSe), 438 Bytes

Meine anderen Antworten lösten das falsche Problem (entschuldigen Sie das Rauschen). Hier ist ein weiterer Versuch in Prolog, der tatsächlich alle Regeln einhält.

:-lib(fd).
a([],[]).
a([H|T],L):-append(H,X,L),a(T,X).
s(E,Z,X,Y,L):-length(E,L),a([[60],M,[58,41,126],T,[126,40,58],W,[62]],E),checklist(=(32),T),length(T,Z),b(M,X-[]),b(W,Y-[]).
b(I,[K:M|R]-E):-(I:K=[47,92|L]:s;I:K=[124|L]:n),M#=N+1,N#>=0,b(L,[K:N|R]-E).
b([61|L],[_:0|R]-E):-b(L,R-E).
b([],[_:0|E]-E).
d(_:N,Y:N):-Y=s;Y=n.
s(W,P):-string_list(W,E),s(E,_,X,Y,L),minimize((maplist(d,X,U),maplist(d,Y,V),s(K,Q,U,V,L)),Q),string_list(P,K).

Tests

(Format: Eingabe, Ausgabe, Zeilenumbruch)

<===:)~         ~(:>
<===:)~         ~(:>

<|||:)~         ~(:||||=|>
</\/\/\:)~ ~(:/\/\/\/\=/\>

<=|=:)~         ~(:||||=|>
<=/\=:)~   ~(:/\/\/\/\=/\>

<===|:)~         ~(:||=|>
<===/\:)~     ~(:/\/\=/\>

<|=|=|||=|:)~         ~(:=|>
</\=/\=/\/\/\=/\:)~  ~(:=/\>

<||||||:)~         ~(:=|>
</\/\/\/\/\/\:)~  ~(:=/\>

<||||||:)~         ~(:||>
</\/\/\/\/\/\:)~ ~(:/\/\>

<||=||||:)~ ~(:||>
<||=||||:)~ ~(:||>

<||=||||:)~   ~(:||>
</\/\=||||:)~ ~(:||>

<||=||||:)~    ~(:||>
</\/\=||||:)~~(:/\/\>

<||=||||:)~~(:||>
<||=||||:)~~(:||>

Erklärungen

  • Das Hauptprädikat ist s/2, das die Eingabe als erstes Argument verwendet und das Ergebnis mit dem zweiten Argument (beiden Zeichenfolgen) aufhebt. Die Eingabe wird in eine Liste von Zeichencodes umgewandelt E.

  • Dann s(E,Z,X,Y,L)destructures die Liste in den folgenden Elementen:

    • Z Anzahl der Leerzeichen zwischen den Schlangen
    • Xund Yabstrakte Darstellung des linken und rechten Körpers

      Das Format eines Körpers ist eine Liste von n:Noder s:NAusdrücken, wobei Nes sich um eine positive Länge handelt. nMittel normalund sMittel stretched.

    • L Gesamtlänge der Liste

Das Interessante darans/5 ist, dass es in beide Richtungen geht , dh wir können eine Schlange bauen, wenn andere Argumente instanziiert werden:

    s(E,5,[n:3],[s:2,n:7,s:1],_),string_list(S,E).

... unifies `S` with `"<|||:)~     ~(:/\\/\\=|||||||=/\\>"` (backslashes are quoted). This is due to how `b/2` is written, which can parse the character list or generate it.
  • Wir bauen modifizierte linke und rechte Körper, bei denen jeder Teil entweder normal oder gestreckt ist, während der Raum Q, der die neuen Schlangen voneinander trennt , minimiert wird . Die Gesamtlänge der berechneten Zeichenfolge ist begrenzt, sodass die Suche beendet wird.
Core-Dump
quelle
1

Python 2.7.3 427 421 400 371 Bytes

import re,itertools as K
g,o,k='\|+',len,raw_input()
d=k.count(' ')
if d==0:exit(k)
p,x,y,s=re.sub,0,0,map(o,re.findall(g,k))
for e in [A for w in range(o(s)+1)for A in K.combinations(s,w)]:
 v=sum(e)
 if v==d or x<v<d:x,y=v,list(e)
print p(" +",' '*(d-x),p(g,lambda m:('/\\'*o(m.group(0))if y.remove(o(m.group(0)))or True else 1)if o(m.group(0))in y else m.group(0),k))

Code ohne Golf hier -

#!/usr/bin/env python
import sys
import re

def find_dist_combo(li, d):
    #Listing all combinations
    from itertools import combinations as c
    max_dist = -1
    max_dist_combo = []
    for p_len in xrange(1,len(li)+1):
        for e in c(li, p_len):
            e_sum = sum(e)
            cond1 = e_sum == d
            cond2 = max_dist < e_sum < d
            if cond1 or cond2:
                max_dist = e_sum
                max_dist_combo = list(e)
                if cond1:
                    return (max_dist, max_dist_combo)
    return (max_dist, max_dist_combo)

def snakes_foreplay(snakes):
    #find distance
    distance = snakes.count(" ")

    #already kissing
    if distance == 0:
        return snakes

    #find num_stretches
    stretch = map(len, re.findall("\|+", snakes))

    #find lowest combination of numbers
    (e_dist, res_stretch) = find_dist_combo(stretch, distance)

    def sub_callback(m):
        s = m.group(0)
        l = len(s) 
        if l in res_stretch:
            res_stretch.remove(l)
            return '/\\'*l
        return s

    #Resultant substitution
    res_snakes = re.sub("\s+", " "*(distance - e_dist), re.sub("\|+", sub_callback, snakes))

    return res_snakes

if __name__ == "__main__":
    for s in [ip.strip() for ip in sys.stdin]:
        print snakes_foreplay(s)

Testen der Golflösung -

$ python stretchy_snakes.py
[In]  <=  <|=||:)~     ~(:||||>
[Out] =>  </\=||:)~~(:/\/\/\/\>

$ python stretchy_snakes.py
[In]  <=  <|=||:)~             ~(:||||>
[Out] =>  </\=/\/\:)~      ~(:/\/\/\/\>

$ python stretchy_snakes.py
[In]  <=  <|=||:)~     ~(:|||=|>
[Out] =>  </\=||:)~~(:/\/\/\=/\>

$ python stretchy_snakes.py
[In]  <=  <||=||||:)~   ~(:||>
[Out] =>  </\/\=||||:)~ ~(:||>

$ python stretchy_snakes.py
[In]  <=  <|=||:)~~(:||||>
[Out] =>  <|=||:)~~(:||||>

Sicherlich kann dies besser gemacht werden (ich kann nicht herausfinden, wie :)).
Lassen Sie mich wissen, wenn ich beim Golfen etwas Offensichtliches verpasst habe (Es ist mein erster Codegolf, ich mache vielleicht etwas Dummes: P)

Kamehameha
quelle
@ Sp3000 Das ist gut. Ersetzt exitfür sys.exit()(vergessen exitexistiert). Und Sie haben Recht, __import__können entfernt werden, die wie 20 Zeichen beseitigt :)
Kamehameha
Übrigens Faustregel: Für das Aliasing müssen > 6Zeichen ein Aliasing wert sein, wenn Sie es zweimal verwenden, > 3Zeichen, wenn Sie es dreimal verwenden. Ich bin nicht sicher, ob der f=' 'Alias ​​es wert ist (ich zähle zweimal)
Sp3000
@ Sp3000 yep du hast recht. In einer früheren Version hatte ich diese Variable dreimal verwendet. Hat mir noch ein paar Bytes gerettet :) :)
Kamehameha
1

05AB1E , 93 Bytes

#õKDεγʒ'|å]©ε€gxøDgU`XG‘]`âDε˜ODI„| Ãg>‹*}ZQÏε˜ε®˜NèDgyÊi„/\y∍]н©J'/¢Ið¢αð×ý'|¡õK®.ιJIðå≠iI

Viel zu lang ..>.>

Probieren Sie es online aus oder überprüfen Sie alle Testfälle oder überprüfen Sie alle möglichen Ergebnisse für alle Testfälle .

Erläuterung:

#õK                   # Split the (implicit) input by one or multiple adjacent spaces
                      # (we now have both snakes as separated items
                      #  - if any spaces were in the input-string)
   D                  # Duplicate this list
    ε                 # Map both snakes to:
     γ                #  Split the snake into chunks of the same character-type
      ʒ'|å]          '#  And only leave the chunks of "|" characters
    ©                 #  Store this list in variable `r` (without popping)
     ε                #  Map the "|" chunks of both snakes again:
      g              #  Get the length of each chunk of "|"
        xø            #  Pair each length with double itself
          DgU`XG‘   #  Create all possible combinations for the current snake
     ]`â              # After the map: create all possible combinations for both snakes
        ε             # Map over each possible combination
         ˜O           #  Get the flattened sum
            I„| Ãg    #  Count the amount of "|" and spaces in the input
                  >‹  #  Check if it's smaller than or equal to this sum
                      #  (1 if truthy; 0 if falsey)
           D        * #  And multiply it by the sum
        }ZQ           # After the map, get the positions of the largest flattened sum,
                      # still below (or equal to) the amount of "|" and spaces combined
       D   Ï          # And only keep those combinations
ε                     # Then map over the remaining combinations
 ˜ε                   #  Flatten it, and map over each value `y`
   ®˜Nè               #   Get the `N`'th part of the snakes
                      #   (where `N` is the index of the map for the current combination)
       D              #   Duplicate this "|"-part
        gyÊi          #   If the length of this "|"-part is not equal to the map-value:
            „/\       #    Push the string "/\"
               y     #    Extended to a size equal to the map-value
                      #   (implicit else:
                      #    use the duplicated value)
                    # After the map: only leave the first (since we don't have
                      # to output all possibilities)
 ©                    # Store it in variable `r` (without popping)
  J'/¢               '# Count the amount of "/" in it
      Ið¢             # Count the amount of spaces in the input
         α            # Get the difference between those
          ð×ý         # And join the list of snakes by that many spaces
'|¡õK                '# Then split by one or multiple adjacent "|"
     ®.ι              # Interleave it with the modified parts of variable` r`
        J             # And join everything together to a single string
Iðå≠i                 # If the input didn't contain any spaces:
     I                #  Output the input instead
                      # (implicit else:
                      #  output the top of the stack before this if)
Kevin Cruijssen
quelle