Ottimizza le provette ASCII


13

Ti vengono date un sacco di provette ASCII, il tuo compito è ridurre il numero di provette utilizzate.

Ogni provetta si presenta così:

|  |
|  |
|  |
|~~|
|  |
|  |
|  |
|  |
|__|

Ovviamente, ~~è il livello dell'acqua. La provetta può anche essere vuota, nel qual caso non ci sono ~~caratteri all'interno. Il tubo singolo può contenere fino a 8 unità di livello dell'acqua.

Viene fornito un numero finito di provette con diversi livelli di acqua all'interno. Devi versare l'acqua nel minor numero possibile di provette e produrre il risultato.

|  | |  | |  | |  |         |~~| |  |
|  | |  | |  | |  |         |  | |  |
|  | |~~| |  | |  |         |  | |  |
|~~| |  | |  | |  |         |  | |~~|
|  | |  | |  | |  | ------> |  | |  |
|  | |  | |  | |  |         |  | |  |
|  | |  | |~~| |  |         |  | |  |
|  | |  | |  | |  |         |  | |  |
|__| |__| |__| |__|         |__| |__|

 05 + 06 + 02 + 00  ------>  08 + 05

Come puoi vedere, le provette sono separate da un unico spazio. I tubi vuoti non devono essere mostrati in uscita. Questo è il codice golf, quindi vince il codice con il minor numero di byte.

Casi di prova: http://pastebin.com/BC0C0uii

Buon golf!


Possiamo ridistribuire anche l'acqua? Ad esempio 7 + 6 sarebbe un output valido per il tuo esempio?
Martin Ender,

@MartinEnder Dovresti usare il minor numero possibile di tubi. Penso che sia accettabile in questo caso.
Jacajack,

@StewieGriffin Non ho ancora visto nulla di simile qui, quindi se questo è un po 'un duplicato, mi dispiace
Jacajack,

È consentito lo spazio bianco finale?
PurkkaKoodari,

Titolo migliore: "Ottimizzatore ASCII bambini in provetta"
Ottimizzatore

Risposte:



4

JavaScript (ES6), 159 148 byte

s=>s.replace(/~~|\n/g,c=>1/c?i++:n+=7-i,n=i=-1)&&`012345678`.replace(/./g,i=>`|${g(+i)}| `.repeat(n>>3)+`|${g(~n&7^i)}|
`,g=i=>i?i>7?`__`:`  `:`~~`)

Emette un avanzamento riga finale. Modifica: salvato 11 byte con l'aiuto di @Arnauld.


s.replace(/~~/g,(_,i)=>n+=9-i/s.indexOf`\n`|0,n=0)dovrebbe salvare 4 byte. È possibile che si desideri inizializzare n su -1 e utilizzare n>>3e ~n&7^isalvare un altro byte.
Arnauld,

@Arnauld Grazie per l' -1idea ma sono stato in grado di migliorare l' replaceidea.
Neil,

1
Bello! Non ho mai capito che 1/"\n"fosse vero.
Arnauld,

@Arnauld Beh, era solo un ulteriore byte di glassa sulla torta ...
Neil

3

Perl, 150 byte

149 byte di codice + -nflag.

$l+=9-$.for/~~/g}if($l){$%=($v=$l/8)+($r=$l!=8);say"|~~| "x$v.($@="|  | ")x$r;say$:=$@x$%for$l%8..6;say$@x$v."|~~|"x$r;say$:for 2..$l%8;say"|__| "x$%

Non spiegherò tutto il codice, solo alcune cose:
$l+=9-$.for/~~/gconta quanta acqua c'è nell'input.
La seconda parte del codice stampa l'output. L'idea è quella di mettere il maggior numero possibile di tubi completamente riempiti e un ultimo che contenga l'acqua rimasta (se presente). Quindi l'algoritmo è in 4 parti: stampa la prima linea di acqua (la parte superiore dei tubi): say"|~~| "x$v.($@="| | ")x$r. Quindi stampare parti vuote di tubi fino a raggiungere il livello di acqua dell'ultimo tubo: say$:=$@x$%for$l%8..6. Quindi stampare il livello in cui l'acqua ultima tubo è: say$@x$v."|~~|"x$r. Poi, stampare tutti i livelli restanti "vuoti": say$:for 2..$l%8;. E, infine, stampare la linea di fondo: say"|__| "x$%.
I nomi delle variabili rendono difficile da leggere ( $%, $@, $:), ma permette di parole chiave come xefor da scrivere dopo la variabile senza spazio.

Per eseguirlo:

perl -nE '$l+=9-$.for/~~/g}if($l){$%=($v=$l/8)+($r=$l!=8);say"|~~| "x$v.($@="|  | ")x$r;say$:=$@x$%for$l%8..6;say$@x$v."|~~|"x$r;say$:for 2..$l%8;say"|__| "x$%' <<< "|  | |  | |  | |  |
|  | |  | |  | |  |
|  | |~~| |  | |  |
|~~| |  | |  | |  |
|  | |  | |  | |  |
|  | |  | |  | |  |
|  | |  | |~~| |  |
|  | |  | |  | |  |
|__| |__| |__| |__| "

Non sono molto soddisfatto di quanto sia lunga questa risposta. Ho cercato di trarre il meglio dal mio algoritmo, ma probabilmente un approccio diverso potrebbe essere più breve. Proverò a lavorarci presto.


@JamesHolderness Ho provato tutti i casi di test (e ho riprovato ora perché mi hai fatto dubitare) e mi sembra che vada bene. "L'ultimo" è quello con 3 tubi: 2 con livello dell'acqua a 4 e 1 con acqua al livello 2, giusto? Se è così, allora l'ho provato e dà lo stesso output di pastbin
Dada,

@JamesHolderness Oh giusto, spiega molto! Grazie :)
Dada,

3

Befunge, 144 138 byte

9>1-00p>~$~2/2%00gv
 |:g00_^#%4~$~$~+*<
$< v01!-g01+*8!!\*!\g00::-1</8+7:<p01-1<9p00+1%8-1:_@#:
_ ~>g!-1+3g:"|",,," |",,:>#^_$55+,10g:#^_@

Provalo online!

Le prime due righe elaborano l'input, praticamente ignorando tutto tranne il primo carattere in ogni tubo che potrebbe essere un indicatore di livello. Prendiamo il valore ASCII di quel carattere, dividiamo per 2 e mod 2 (dandoci 1 o 0 a seconda che ci troviamo su un indicatore di livello o meno), moltipliciamo quello per il numero di riga (contando da 8, quindi dandoci il valore di livello per quel tubo) e aggiungerlo a un totale parziale.

L'output viene gestito sulle seconde due righe, iniziando essenzialmente dall'estrema destra della terza riga. Prima calcoliamo il numero di tubi prendendo il livello totale dell'acqua più 7 diviso per 8. Quindi quando si scorre sopra le file di tutti i tubi, calcoliamo il carattere da visualizzare all'interno di un tubo specifico ( t , contando fino a 0) per un data riga ( r , conto alla rovescia da 8 a 0) come segue:

last_level = (total_water - 1)%8 + 1
level      = last_level*!t + 8*!!t
char_type  = !(level - r) - !r

Il calcolata char_type è -1 per la riga in basso (la base del tubo), 0 per una qualsiasi altra area che non è un livello di acqua e 1 per il livello dell'acqua. Può quindi essere usato come semplice ricerca di una tabella per il carattere appropriato da emettere (puoi vedere questa tabella all'inizio della riga 4).


2

Haskell, 186 byte

import Data.Lists
z=[8,7..0]
f x|s<-sum[i*length j-i|(i,j)<-zip z$splitOn"~~"<$>lines x],s>0=unlines$(\i->(#i)=<<(min 8<$>[s,s-8..1]))<$>z|1<2=""
l#i|i==l="|~~| "|i<1="|__| "|1<2="|  | "

Esempio di utilizzo:

*Main> putStr $ f "|  | |  | |  | |  |\n|  | |  | |  | |  |\n|  | |~~| |  | |  |\n|~~| |  | |  | |  |\n|  | |  | |  | |  |\n|  | |  | |  | |  |\n|  | |  | |~~| |  |\n|  | |  | |  | |  |\n|__| |__| |__| |__|"
|~~| |  | 
|  | |  | 
|  | |  | 
|  | |~~| 
|  | |  | 
|  | |  | 
|  | |  | 
|  | |  | 
|__| |__| 

Mette uno spazio finale su ogni riga. Come funziona:

              lines x      -- split the input string at newlines             
      splitOn"~~"<$>       -- split every line on "~~"
    zip z                  -- pair every line with its water level, i.e.
                           -- first line = 8, 2nd = 7 etc.
   [i*length j-i|(i,j)   ] -- for each such pair take the number of "~~" found
                           -- times the level
 s<-sum                    -- and let s be the sum, i.e. the total amount of water

  s>0                      -- if there's any water at all

          [s,s-8..1]       -- make a list water levels starting with s
                           -- down to 1 in steps of 8
       min 8<$>            -- and set each level to 8 if its greater than 8
                           -- now we have the list of water levels for the output
  \i->(#i)=<<(  )<$>z      -- for each number i from 8,7..0 map (#i) to the
                           -- list of output water levels and join the results
unlines                    -- join output lines into a single string (with newlines)

l#i                        -- pick a piece of tube:
                           --  |__|  if l==0
                           --  |~~|  if l==i
                           --  |  |  else



  |1<2=""                  -- if there's no water in the input, return the
                           -- empty string

Il dolore principale era la mancanza di una funzione che conta la frequenza con cui si verifica una sottostringa in una stringa. C'è countdentro Data.Text, ma importarlo porta a un sacco di conflitti di nomi che sono troppo costosi per essere risolti.


1

Python, 261 byte

i=input().split('\n')
t=0
R=range(9)[::-1]
for n in R:t+=i[n].count('~')/2*(8-n)
m=t%8
e=t/8
o=t/8+1
T='|~~| '
b='|  | '
B='|__| '
n='\n'
if m:
 print T*e+b
 for n in R:
    if n==m:print b*e+T
    else:print b*o
 print B*o
elif t<1:1
else:print T*e+(n+b*e)*7+(n+B)*e

Sento che c'è qualcosa che mi manca. Inoltre, se un gruppo di newline fosse accettabile per l'output vuoto, potrei perdere alcuni byte. Accetta input come '| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n|__| |__| |__|'.


1

Rubino , 139 byte

(138 byte di codice più un byte per il -n)

n||=0;b=gsub(/~~/){n=n+9-$.}[0,5];END{8.times{|i|puts (b*(n/8)).tr(?_,i>0??\ :?~)+(n%8>0?b.tr(?_,(8-i==n%8)??~:?\ ):"")};puts b*((n+7)/8)}

Provalo online!

Alcune spiegazioni:

Questo programma richiede il -npassaggio.

n - contatore dell'acqua.

b- Modello per la costruzione di tubi; è uguale a"|__| "

i - Indice di linea corrente durante la costruzione del tubo.

gsub(/~~/){... }- Questo abusa gsubdi contare semplicemente il livello dell'acqua. gsubin realtà si espande a Kernel.gsub, il che equivale a $_.gsub!. Questo manipola inutilmente la linea corrente ( $_); tuttavia, consente un'assegnazione più concisa di b=... [0,5]anziché b=$_[0,5].

n=n+9-$.- Per misurare il livello dell'acqua, l'espressione utilizza la variabile predefinita $., che porta il numero della riga di input corrente . Questo mi ha permesso di perdere la variabile esplicita del ciclo.

b=gsub(/~~/){... }[0,5]- memorizza nella cache la parte inferiore del tubo più a sinistra come modello. (Mi sembra un po 'come il modello "Elefante al Cairo" perché la linea di fondo vince.)
Dato che il fondo del tubo non mostra mai acqua, gsubnon sostituirà nulla quando ci siamo; quindi alla fine, è bsempre uguale "|__| ".

END{... }- Viene chiamato dopo l'elaborazione dell'intero flusso di input. Uso questa fase per costruire i tubi target.

i>0??\ :?~- è semplicemente una scorciatoia per i > 0 ? " " : "~".

Aggiornamento 1: Aggiunti dettagli sulle variabili, ilgsub inganno e la fase END{...}

Aggiornamento 2: (± 0 byte complessivi)

  • Usa n||=0invece din=n||0 (-1 byte)
  • Ha preso malus per -n (+1 byte)

0

Python 3, 404 byte

Questo programma crea l'intera potenza prevista con i livelli dell'acqua sia in formato ASCII che numerico.

w,x,y=[],[],[];a,b,s=" ------> ","~","";y=input().split("\n")
for i in [i for i in zip(*y) if "_" in i][::2]:w+=[8-i.index(b)] if b in i else [0]
u=sum(w)
while u:x+=[[8],[u]][u<8];u-=x[-1]
for i,k in enumerate(y):
    s+=k+"%s"%[a," "*9][i!=4]
    for j,l in enumerate(x):
        c=["  ","__"][i==8];s+="|%s| "%(c,b*2)[l==8-i]
    s+="\n"
s+="\n"
for i in w:s+=" %02d  "%i
s+="\b"+a
for i in x:s+=" %02d  "%i
print(s)
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.