Embrassez les serpents tendres

57

Un serpent extensible ressemble à ceci:

<||=|||:)~

Chaque séquence distincte de barres verticales ( |) dans un serpent extensible, appelée partie extensible , peut être étendue individuellement jusqu'à deux fois sa largeur et est dessinée avec des barres obliques alternées ( /, \) une fois déployée.

Le serpent ci-dessus a deux telles portions extensibles, ce qui lui donne quatre poses possibles:

<||=|||:)~

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

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

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

La forme générale d'un serpent extensible dans sa pose la moins étirée est définie par cette expression rationnelle :

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

Ce qui peut être écrit en mots comme:

<, suivi par un nombre quelconque de séquences de |'s jointes avec des =signes, suivi de :)~.

Ainsi <|:)~et <||:)~et <|=|:)~et <|=|=||=|||||=||:)~sont des serpents élastiques, mais <=:)~et <=|:)~et <||=:)~et <|==||:)~ne sont pas.

Les serpents extensibles peuvent également faire face à gauche au lieu de droite, par exemple ~(:|||=||>. Les formes sont les mêmes, juste en miroir.

Défi

Ecrivez un programme qui prend une seule ligne de deux serpents extensibles se faisant face, avec un certain nombre d'espaces entre eux. Les deux serpents seront dans leur pose la moins étirée (toutes les barres verticales, pas de barres obliques). La chaîne commence par la queue du serpent dirigé vers la droite et se termine par celle du serpent dirigé vers la gauche (vous pouvez éventuellement supposer qu'il existe également une nouvelle ligne).

Par exemple, voici une entrée possible avec cinq espaces entre les serpents:

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

J'utilise des points ( .) au lieu des espaces réels pour plus de clarté.

Zéro espace entre les serpents est également une entrée valide:

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

Nous disons que les serpents s'embrassent lorsque leurs langues se touchent de la sorte.

Votre programme doit étendre une combinaison des parties extensibles des deux serpents de manière à ce qu’ils aient le moins d’espaces possibles (sans se chevaucher), c’est-à - dire que les serpents s’embrassent le plus possible .

Les deux queues des serpents sont fixes mais leurs têtes et leurs corps peuvent bouger - à droite pour le serpent à droite, à gauche pour le serpent à gauche - en fonction des portions étendues qui ont été étendues.

La sortie de votre programme est une chaîne simple ligne (plus une nouvelle ligne facultative) qui montre les serpents aussi près que possible d'embrasser, avec des barres obliques alternées au lieu de barres verticales pour les portions extensibles qui ont été étendues.


Par exemple, la sortie pour <|=||:)~.....~(:||||>(à partir de ci-dessus) serait:

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

C’est la seule solution ici car avec toute autre combinaison de parties extensibles étendues, les serpents se chevaucheraient ou seraient plus éloignés des baisers.


S'il existe plusieurs solutions possibles, la sortie peut être l'une d'entre elles.

Par exemple, si l’entrée était

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

la sortie pourrait être

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

ou

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

N'oubliez pas qu'il ne sera pas toujours possible de faire s'embrasser les serpents, mais vous devez toujours les rapprocher le plus possible.

Par exemple, si l’entrée était

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

la sortie pourrait être

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

ou

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

Si les serpents s'embrassent déjà, la sortie sera la même que l'entrée. par exemple

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

En général, la sortie sera la même que l'entrée si l'extension d'une partie élastique rend les serpents superposés. par exemple

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

Remarques

  • Prend les entrées à partir de stdin ou de la ligne de commande, comme d'habitude, ou écrit une fonction prenant une chaîne. Imprimer ou renvoyer la sortie.
  • Vous pouvez utiliser des points ( .) dans les entrées et les sorties à la place d'espaces ( ) si vous préférez.
  • Il est seulement important que les barres obliques alternent dans la séquence de barres verticales qu'elles ont remplacées. Leur ordre dans le serpent en général ou si une barre oblique en avant ou en arrière vient en premier n'a pas d'importance.
  • Les portions extensibles ne peuvent pas s’allonger partiellement, c’est exactement une extension double ou pas du tout.

Notation

C'est du code-golf . La soumission la plus courte en octets l'emporte. Tiebreaker est une réponse plus tôt.

Les passe-temps de Calvin
la source
17
Snex Education 101 - Comment s'embrasser correctement
Optimiseur
45
"Nous disons que les serpents s'embrassent quand leurs langues se touchent comme ça." Qu'est-ce que je lis ...
Fataliser
8
Alors les serpents ne font que le français?
Optimiseur
3
@PeterTaylor Eh bien, "en miroir", pas "inversé" (sinon >, ne deviendrait pas non <plus pareil, identique pour (et )), mais il a également déclaré: "Il est seulement important que les barres obliques alternent dans la séquence de barres verticales qu'elles ont remplacées. serpent en général ou si une barre oblique avant ou arrière vient en premier n'a pas d'importance. "
Martin Ender
7
@ qwr Imagination.
Les passe-temps de Calvin

Réponses:

9

CJam, 87 71 70 68 octets

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

Essayez-le en ligne dans l' interprète CJam .

Comment ça fonctionne

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
la source
19

Retina , 209 107 99 97 92 octets

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

À des fins de comptage, chaque ligne est placée dans un fichier séparé, mais vous pouvez exécuter le code à partir d'un seul fichier avec l' -sindicateur.

Rassembler les meilleures fonctionnalités de .NET regex et Retina: groupes d'équilibrage, recherche de longueur arbitraire et substitution répétée de regex.

Essentiellement, le long regex code une solution valide et le backtracker du moteur de regex en trouve l’un des meilleurs pour moi.

Explication

Voyons d’abord comment trouver une solution valide (ne produisant pas nécessairement le bon résultat) avec une expression rationnelle. Nous pouvons utiliser les groupes d'équilibrage .NET pour nous aider à compter les parties élastiques. Considérez le regex plus simple suivant:

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

Nous pouvons comprendre cela.

\S+( )+.+

Cela correspond à la chaîne entière, en insérant une capture dans la 1pile de groupes pour chaque espace de l'entrée. Nous allons utiliser cette pile pour nous assurer que les parties extensibles occupent exactement l'espace capturé dans ces groupes.

Suivant est un lookbehind. Le problème, c’est que les repères sont assortis de droite à gauche dans .NET (c’est ce que vous devriez lire). Cela nous donne l’occasion de parcourir la chaîne une seconde fois, en déterminant s’il existe un sous-ensemble de partie extensible qui correspond au nombre d’espaces correspondants. En passant par le regard de droite à gauche:

>

Ceci est juste pour nous assurer que nous partons réellement de la fin de la chaîne (la queue du serpent).

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

Pour chaque partie extensible, cela correspond simplement à la partie entière sans rien faire ( \|+), ou bien à la partie entière tout en faisant apparaître des captures de pile 1( (?<-1>\|)*). Cette alternance garantit que nous ne pouvons que prolonger entièrement une partie extensible ou la laisser inchangée, et ne pas avoir de choses comme |/\|. Ensuite, nous passons à la prochaine partie extensible avec [^|]+.

(?(1)!)^

Enfin, nous nous assurons que nous avons traversé toute la chaîne (les deux serpents) et que la pile 1est complètement vide. C'est-à-dire que nous avons trouvé un sous-ensemble de parties extensibles qui correspond exactement au nombre d'espaces capturés précédemment.

Le backtracker parcourt la chaîne en essayant toutes les combinaisons de parties non modifiées et étendues jusqu'à ce que le problème de la somme des sous-ensembles soit résolu. Si un tel sous-ensemble n'existe pas, la recherche en arrière échouera. Ainsi, le backtracker retournera à la \S+( )+.+pièce et essaiera de capturer un espace de moins avec ( )+(ce qui sera simplement couvert par .+). En raison de la gourmandise de, +nous essayons donc de remplir autant d'espaces que possible.

Vous pouvez vérifier la validité de cette approche avec cette substitution légèrement modifiée:

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

Ce qui vous donnera une chaîne =spaces=avec exactement le nombre d'espaces pouvant être remplis avec les serpents donnés.

J'ai dû ajouter quelques astuces pour développer les |s corrects . Fondamentalement, je veux remplacer tous les |s qui ont été appariés en utilisant la (?<-1>\|)+branche. L'idée est de faire correspondre un caractère individuel, de placer le solveur dans un lookaround et de définir un indicateur si la correspondance se trouve à l'intérieur de cette branche. Si cet indicateur n'a pas été défini, nous invaliderons la correspondance à la fin pour éviter le remplacement d'autres caractères.

Pour ce faire, nous utilisons un tas de corrections imbriquées. Encore une fois, les recherches d'arrière-plan de longueur variable .NET sont appariées de droite à gauche. Par conséquent, si nous imbriquons des recherches d'antécédents, nous pouvons laisser le moteur des expressions rationnelles traverser la chaîne plusieurs fois. Pour des raisons liées au golf, le solveur est inversé dans ma solution actuelle (en partant de la fin, ramasser les espaces de droite à gauche, puis en résolvant la somme du sous-ensemble de gauche à droite), mais sinon la structure du solveur est exactement la même. . Disséquons la regex complète:

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

Nous faisons correspondre un seul caractère, puis capturons le reste de la chaîne et déplaçons le curseur à la fin de la chaîne. Nous utiliserons ce groupe 1plus tard pour vérifier dans le solveur si nous en sommes à la position du match.

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

Cela ressemble à la première partie du solveur simple ci-dessus, sauf que nous prenons les espaces de droite à gauche. Le retour en arrière du nombre d'espaces fonctionne exactement comme avant, sauf que nous utilisons 5maintenant le groupe .

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

C’est la même chose que précédemment, sauf que nous allons de gauche à droite, et chaque fois que nous correspondons à un |dans la branche en expansion, nous vérifions si c’est celui qui correspond le mieux à

(?=\1())?

C'est une option optionnelle. Il essaie à 1nouveau de faire correspondre le groupe (ce qui, ici, n’est possible que si nous sommes juste après le caractère mis en correspondance), et si nous le faisons, nous capturons une chaîne vide dans le groupe 4, ce qui indique que nous avons trouvé le caractère actuel dans un groupe. des bits développés. Si \1ne correspond pas, 4rien ne sera capturé, et le système ?s'assurera que la recherche échouée n'aura aucune incidence sur le solveur.

Enfin, après que toute la résolution soit terminée, nous vérifions simplement \4si cette apparence a été utilisée. Si c'est le cas, nous voulons remplacer le caractère actuel par /\.

Une difficulté demeure: supprimer la bonne quantité d'espaces. Le moyen le plus rapide que j'ai trouvé jusqu'à présent consiste à insérer un espace avec le /\, puis à supprimer un espace entre les langues pour chacun de ces espaces dans une étape distincte:

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

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

C'est une fonction qui prend une chaîne en tant que paramètre et retourne une chaîne.

Tests en ligne: http://ideone.com/uhdfXt

Voici la version lisible:

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

Dans la version golfée, la fonction principale est l’équivalent de la KISSfonction ci-dessus et la COMBINATIONSfonction a été intégrée.

Cristian Lupascu
la source
Echoue lors de la saisie <|=||:)~~(:||||>, spécifiée par la spécification comme entrée valide.
Valeur d'encre
6

Python, 205 octets

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","/\\")

Avoir un seul lambda a l'air soigné et tout, mais je suis presque certain que ce n'est pas la meilleure façon de faire. Mais je poste ceci car c'est tout ce que j'ai jusqu'ici qui semble à moitié décent.

C'est un simple force brute sur tous les remplacements possibles |avec /\, en filtrant les configurations non valides. Le seul peu propre , je suppose que nous ne remplaçons pas vraiment tout |avec /\directement - nous avons d' abord remplaçons |avec Xet laissez tomber un à .partir du milieu pour chaque remplacement, prenez la chaîne de longueur minimale sur toutes les chaînes valides, puis remplacer les Xs avec /\.

J'ai essayé quelques autres approches, y compris récursives, mais elles se sont révélées assez compliquées. J'ai aussi appris re.splitqu'actuellement, les chaînes vides ne se divisaient pas, ce qui était regrettable, car l'une de mes idées impliquait la séparation des \bmots.

Sp3000
la source
5

Mathematica, 381 octets

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~"~"&

Fonction pure prenant la chaîne comme argument. Les attentes. plutôt qu'entre les serpents.

Je ne pensais pas que ce serait si grave… Voici ce que j'avais avant de le briser ensemble et de tout fixer.

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[#, "~"] &

Voici un exemple avec explication:

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
la source
Facilement réduit à 355 en commençant par a=StringReplace;b=StringSplit;c=StringLength;d=Total;ceux qui sont nécessaires ailleurs à l'intérieur, puis en les remplaçant: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 octets

Mes autres réponses résolvaient le mauvais problème (désolé pour le bruit). Voici une autre tentative dans Prolog qui respecte toutes les règles.

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

Des tests

(format: entrée, sortie, nouvelle ligne)

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

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

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

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

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

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

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

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

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

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

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

Des explications

  • Le prédicat principal est s/2, qui prend l’entrée comme premier argument et délie le résultat avec le deuxième argument (les deux chaînes). L'entrée est converti en une liste de codes de caractères, E.

  • Ensuite, s(E,Z,X,Y,L)décomposez la liste en éléments suivants:

    • Z nombre d'espaces entre les serpents
    • Xet Y, représentation abstraite des corps gauche et droit

      Le format d'un corps est une liste n:Nou s:Nexpressions, où Nest une longueur positive; ndes moyens normalet des smoyens stretched.

    • L longueur totale de la liste

Ce qui est intéressant,s/5 c’est que cela va dans les deux sens , c’est-à-dire que nous pouvons construire un serpent si d’autres arguments sont instanciés:

    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.
  • Nous construisons des corps gauche et droit modifiés dans lesquels chaque partie est normale ou étirée, tout en minimisant l'espace Qqui sépare les nouveaux serpents. La longueur totale de la chaîne calculée est limitée de sorte que la recherche se termine.
coredump
la source
1

Python 2.7.3 427 421 400 371 octets

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 non-golfé ici -

#!/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)

Test de la solution golfée -

$ 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] =>  <|=||:)~~(:||||>

Cela peut sûrement être mieux fait (je ne vois pas comment :)).
Faites-moi savoir si j'ai oublié quelque chose d'évident en jouant au golf (c'est mon premier code-golf, je suis peut-être en train de faire une bêtise: P)

Kamehameha
la source
@ Sp3000 Cest un bon. Remplacé exitpour sys.exit()(oublié exitexisté). Et vous avez raison, __import__peut être supprimé, cela éliminé comme 20 caractères :)
Kamehameha
En fait, la règle de base: pour que vous > 6utilisiez l' aliasing, vous avez besoin que les caractères valent la peine d'être aliasés si vous l'utilisez deux fois, les > 3caractères si vous l'utilisez trois fois. Je ne suis pas sûr que le f=' 'pseudonyme en vaut la peine (je compte deux fois)
Sp3000
@ Sp3000 ouais vous avez raison. Dans une version antérieure, j'avais utilisé cette variable trois fois. M'a sauvé quelques octets :) :)
Kamehameha
1

05AB1E , 93 octets

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

Bien trop long ..>.>

Essayez-le en ligne ou vérifiez tous les tests ou vérifiez tous les résultats possibles pour tous les tests .

Explication:

#õ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
la source