Fai il bacio dei serpenti elastici


57

Un serpente elastico assomiglia a questo:

<||=|||:)~

Ogni sequenza separata di barre verticali ( |) in un serpente elastico, noto come una porzione elastica , è estendibile individualmente a due volte la sua larghezza e viene disegnata con barre alternate ( /, \) una volta estese.

Il particolare serpente sopra ha due di queste porzioni elastiche, dandogli quattro possibili pose:

<||=|||:)~

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

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

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

La forma generale di un serpente elastico nella sua posa meno allungata è definita da questa regex :

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

Che può essere dichiarato in parole come:

<, Seguito da un numero di sequenze di |'s unito con =segni, seguita da :)~.

Così <|:)~e <||:)~e <|=|:)~e <|=|=||=|||||=||:)~sono serpenti elastici, ma <=:)~e <=|:)~e <||=:)~e <|==||:)~non lo sono.

I serpenti elastici possono anche essere rivolti a sinistra anziché a destra, ad es ~(:|||=||>. Le forme sono le stesse, solo speculari.

Sfida

Scrivi un programma che includa una stringa a riga singola di due serpenti elastici uno di fronte all'altro, con un numero di spazi in mezzo. Entrambi i serpenti saranno nella loro posizione meno allungata (tutte le barre verticali, senza barre). La stringa inizierà con la coda del serpente rivolto a destra e terminerà con la coda del serpente rivolto a sinistra (si può facoltativamente supporre che ci sia anche una nuova riga finale).

Ad esempio, ecco un possibile input con cinque spazi tra i serpenti:

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

Sto usando punti ( .) invece di caratteri spaziali reali per chiarezza.

Anche lo spazio zero tra i serpenti è un input valido:

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

Diciamo che i serpenti si baciano quando le loro lingue si toccano in questo modo.

Il tuo programma deve estendere una combinazione delle porzioni elastiche di entrambi i serpenti in modo tale che i serpenti abbiano il minor numero possibile di spazi tra loro (senza sovrapposizioni), ovvero tali che i serpenti siano il più vicino possibile ai baci .

Entrambe le code dei serpenti sono fisse ma le loro teste e i loro corpi possono muoversi - a destra per il serpente rivolto a destra, a sinistra per il serpente rivolto a sinistra - in base a quali porzioni elastiche sono state estese.

L'output del tuo programma è la stringa a riga singola (più la nuova riga finale opzionale) che mostra i serpenti il ​​più vicino possibile al bacio, con barre alternate disegnate al posto di barre verticali per porzioni elastiche che sono state estese.


Ad esempio, l'output per <|=||:)~.....~(:||||>(dall'alto) sarebbe:

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

Questa è l' unica soluzione qui perché con qualsiasi altra combinazione delle porzioni elastiche estese, i serpenti si sovrapporrebbero o sarebbero più lontani dai baci.


Se sono possibili più soluzioni, l'output può essere una qualsiasi.

Ad esempio, se l'input fosse

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

l'output potrebbe essere

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

o

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

Ricorda che non sarà sempre possibile baciare i serpenti, ma devi comunque avvicinarli il più possibile.

Ad esempio, se l'input fosse

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

l'output potrebbe essere

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

o

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

Se i serpenti si stanno già baciando, l'output sarà lo stesso dell'input. per esempio

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

In generale, l'output sarà lo stesso dell'input se l'estensione di qualsiasi porzione elastica fa sovrapporre i serpenti. per esempio

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

Appunti

  • Prende l'input da stdin o dalla riga di comando come al solito, oppure scrive una funzione che accetta una stringa. Stampa o ritorna l'output.
  • Se preferisci, puoi usare i punti ( .) nell'input e output al posto degli spazi ( ).
  • È importante solo che le barre si alternino all'interno della sequenza di barre verticali che hanno sostituito. Il loro ordine nel serpente in generale o se viene prima una barra in avanti o indietro non importa.
  • Le porzioni elastiche non possono estendersi a metà - è esattamente doppia o nessuna estensione.

punteggio

Questo è code-golf . Vince l'invio più breve in byte. Tiebreaker è la risposta precedente.


17
Snex Education 101 - Come baciarsi correttamente
Optimizer

45
"Diciamo che i serpenti si baciano quando le loro lingue si toccano in questo modo." Cosa sto leggendo ...
Fatalizza il

8
Quindi i serpenti fanno solo il francese?
Ottimizzatore

3
@PeterTaylor Bene, "specchiato", non "invertito" (altrimenti >non sarebbe <nemmeno lo stesso, lo stesso per (e )), ma dice anche "È importante solo che le barre si alternino all'interno della sequenza di barre verticali che hanno sostituito. serpente in senso lato o se viene prima una barra in avanti o all'indietro, non importa.
Martin Ender,

7
@qwr Imagination.
Calvin's Hobbies,

Risposte:


9

CJam, 87 71 70 68 byte

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

Provalo online nell'interprete CJam .

Come funziona

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.

19

Retina , 209 107 99 97 92 byte

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

Ai fini del conteggio, ogni riga va in un file separato, ma è possibile eseguire il codice da un singolo file con il -sflag.

Riunire le migliori funzionalità di .NET regex e Retina: gruppi di bilanciamento, lookbehinds di lunghezza arbitraria e ripetute sostituzioni di regex.

In sostanza, il regex lungo codifica una soluzione valida e il backtracker del motore regex trova uno di quelli ottimali per me.

Spiegazione

Innanzitutto, consideriamo come possiamo trovare una soluzione valida (che non produce necessariamente l'output corretto) con una regex. Possiamo usare i gruppi di bilanciamento di .NET per aiutarci a contare le parti elastiche. Considera la seguente regex più semplice:

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

Possiamo disertarlo.

\S+( )+.+

Questo corrisponde all'intera stringa, spingendo un'acquisizione nello 1stack di gruppo per ogni spazio nell'input. Useremo quella pila per assicurarci che le parti elastiche riempiano esattamente lo spazio catturato in quei gruppi.

Il prossimo è uno sguardo dietro. Il trucco è che lookbehinds sono abbinati da destra a sinistra in .NET (quindi è così che dovresti leggerli). Questo ci dà l'opportunità di attraversare la corda una seconda volta, per capire se esiste un sottoinsieme di parte elastica che si somma al numero di spazi corrispondenti. Passando attraverso il lookbehind da destra a sinistra:

>

Questo è solo per garantire che stiamo effettivamente iniziando dalla fine della corda (la coda del serpente).

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

Per ogni parte elastica, questa o corrisponde solo all'intera parte senza fare nulla ( \|+), oppure corrisponde all'intera parte mentre il popping cattura catture dallo stack 1( (?<-1>\|)*). Avere questa alternanza assicura che possiamo solo estendere completamente una parte elastica o lasciarla invariata e non ottenere cose del genere |/\|. Quindi passiamo alla prossima parte elastica con [^|]+.

(?(1)!)^

Infine, ci assicuriamo di aver attraversato l'intera stringa (entrambi i serpenti) e che lo stack 1sia completamente vuoto. Vale a dire che abbiamo trovato un sottoinsieme di parte elastica che si somma esattamente al numero di spazi che abbiamo catturato in precedenza.

Il backtracker andrà avanti e indietro attraverso la stringa provando tutte le combinazioni di parti invariate ed estese fino a quando il problema della somma del sottoinsieme non viene risolto. Se tale sottoinsieme non esiste, il lookbehind fallirà. Ciò farà tornare indietro il backtracker alla \S+( )+.+parte e tenterà di catturare uno spazio in meno con ( )+(che invece sarà solo coperto .+). A causa dell'avidità di +noi, quindi, proviamo a riempire il maggior numero possibile di spazi.

Puoi verificare la validità di questo approccio con questa sostituzione leggermente modificata:

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

Il che ti darà una stringa =spaces=con esattamente il numero di spazi che possono essere riempiti con i serpenti dati.

Ho dovuto aggiungere qualche trucco in più per espandere effettivamente le |s corrette . Fondamentalmente, voglio sostituire tutti gli |s che sono stati abbinati usando il (?<-1>\|)+ramo. L'idea è quella di abbinare un singolo personaggio, mettere il risolutore in uno sguardo e impostare una bandiera se la partita si trova all'interno di quel ramo. Se quella bandiera non è stata impostata invalidiamo la partita alla fine per evitare la sostituzione di altri personaggi.

Per fare questo, usiamo un gruppo di lookaround nidificati. Ancora una volta, i lookbehind di lunghezza variabile di .NET sono abbinati da destra a sinistra, quindi se annidiamo lookaheads e lookbehinds, possiamo permettere al motore regex di attraversare la stringa più volte. Per motivi di golf, il solutore è invertito nella mia soluzione effettiva (a partire dalla fine, raccogliendo gli spazi da destra a sinistra e quindi risolvendo la somma del sottoinsieme da sinistra a destra), ma per il resto la struttura del solutore è esattamente la stessa . Analizziamo la regex completa:

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

Abbiniamo un singolo carattere, quindi catturiamo il resto della stringa e spostiamo il cursore alla fine della stringa. Utilizzeremo questo gruppo in 1seguito per verificare se il solutore è nella posizione della partita.

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

È come la prima parte del semplice risolutore sopra, tranne per il fatto che prendiamo gli spazi da destra a sinistra. Il backtracking del numero di spazi funziona esattamente come prima, tranne per il fatto che ora stiamo usando il gruppo 5.

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

È lo stesso di prima, tranne per il fatto che andiamo da sinistra a destra e ogni volta che abbiniamo a |nel ramo in espansione, controlliamo se è quello a cui è stato abbinato il diritto

(?=\1())?

Questo è un lookahead opzionale. Cerca di abbinare di 1nuovo il gruppo (che, qui, è possibile solo se siamo subito dopo l'abbinamento del personaggio), e se lo facciamo, catturiamo una stringa vuota nel gruppo 4, il che indica che abbiamo trovato il carattere corrente in uno dei bit espansi. Se \1non corrisponde, 4non catturerà nulla e ?garantisce che il lookahead in errore non influenzerà affatto il risolutore.

Alla fine, dopo aver risolto tutto, controlliamo solo \4se questo lookahead è stato usato. In tal caso, vogliamo sostituire il personaggio corrente con /\.

Rimane una difficoltà: rimuovere la giusta quantità di spazi. Il modo più breve per farlo che ho trovato finora è quello di inserire uno spazio insieme a /\e quindi sbarazzarsi di uno spazio tra le lingue per ciascuno di quegli spazi marker in un passaggio separato:

+` (.*~|~.*) 
$1

6

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

Questa è una funzione che accetta una stringa come parametro e restituisce una stringa.

Test online: http://ideone.com/uhdfXt

Ecco la versione leggibile:

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

Nella versione golf, la funzione principale è l'equivalente della KISSfunzione sopra e la COMBINATIONSfunzione è stata incorporata.


Errore nell'input <|=||:)~~(:||||>, che le specifiche menzionano come input valido.
Value Ink

6

Python, 205 byte

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

Avere una singola lambda sembra pulito e tutto, ma sono quasi certo che questo non è il modo migliore per andare. Ma sto pubblicando questo perché è tutto quello che ho finora che sembra mezzo decente.

Questa è una semplice forza bruta su tutte le possibili sostituzioni di |con /\, filtrando le configurazioni non valide. L'unica parte ordinata immagino è che in realtà non sostituiamo qualsiasi |con /\direttamente - per prima cosa sostituiamo |con Xe rilasciare una .dal mezzo per ogni sostituzione, prendere la stringa di lunghezza minima su tutte le stringhe valide, quindi sostituire i Xs con /\.

Ho provato alcuni altri approcci, compresi quelli ricorsivi, ma alla fine sono diventati piuttosto disordinati. Ho anche imparato che re.splitattualmente non si divide su stringhe vuote, il che è stato sfortunato, perché una delle mie idee riguardava la divisione dei \bconfini delle parole.


5

Mathematica, 381 byte

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

Funzione pura che prende la stringa come argomento. Si aspetta .piuttosto che tra i serpenti.

Non pensavo che sarebbe stato così male ... Ecco cosa avevo prima di romperlo insieme e aggiustare tutto.

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

Ecco un esempio di run-through con spiegazione:

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.

Facilmente ridotto a 355 iniziando a=StringReplace;b=StringSplit;c=StringLength;d=Total;e sostituendo quelli necessari in altre parti interne: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 byte

Le mie altre risposte erano risolvere il problema sbagliato (scusate il rumore). Ecco un altro tentativo in Prolog che rispetta effettivamente tutte le regole.

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

test

(formato: input, output, newline)

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

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

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

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

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

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

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

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

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

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

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

spiegazioni

  • Il predicato principale è s/2, che accetta l'input come primo argomento e dissolve il risultato con il secondo argomento (entrambe le stringhe). L'ingresso viene convertito in un elenco di codici di carattere, E.

  • Quindi, s(E,Z,X,Y,L)distrugge l'elenco nei seguenti elementi:

    • Z numero di spazi tra i serpenti
    • Xe Y, rappresentazione astratta dei corpi sinistro e destro

      Il formato di un corpo è un elenco di n:No s:Nespressioni, in cui Nè una lunghezza positiva; nmezzi normale smezzi stretched.

    • L lunghezza totale dell'elenco

Ciò che è interessantes/5 è che va in entrambe le direzioni , cioè possiamo costruire un serpente se vengono istanziati altri argomenti:

    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.
  • Costruiamo corpi sinistro e destro modificati in cui ogni parte è normale o allungata, riducendo al minimo lo spazio Qche separa i nuovi serpenti. La lunghezza totale della stringa calcolata è limitata in modo che la ricerca termini.

1

Python 2.7.3 427 421 400 371 byte

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

Codice non golf qui -

#!/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 della soluzione golfizzata -

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

Sicuramente questo può essere fatto meglio (non riesco a capire come :)).
Fammi sapere se ho perso qualcosa di ovvio mentre giocavo a golf (è il mio primo codegolf, forse sto facendo qualcosa di stupido: P)


@ Sp3000 Questo è buono. Sostituito exitper sys.exit()(dimenticato exit). E hai ragione, __import__può essere rimosso, che è stato eliminato come 20 caratteri :)
Kamehameha,

btw regola empirica: per l'aliasing è necessario che i > 6caratteri valgano la pena aliasing se lo si utilizza due volte, > 3caratteri se lo si utilizza tre volte. Non sono sicuro che f=' 'valga la pena (conto due volte)
Sp3000,

@ Sp3000 sì hai ragione. In una versione precedente avevo usato quella variabile tre volte. Mi ha salvato un altro paio di byte :) :)
Kamehameha il

1

05AB1E , 93 byte

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

Troppo a lungo ..>.>

Provalo online o verifica tutti i casi di test o verifica tutti i possibili risultati per tutti i casi di test .

Spiegazione:

#õ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)
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.