Optimizar los tubos de ensayo ASCII

13

Le dan un montón de tubos de ensayo ASCII, su tarea es reducir el número de tubos de ensayo utilizados.

Cada tubo de ensayo se ve así:

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

Obviamente, ~~es el nivel del agua. El tubo de ensayo también puede estar vacío, en cuyo caso no hay ~~caracteres dentro. Un solo tubo puede contener hasta 8 unidades de nivel de agua.

Se le da un número finito de tubos de ensayo con diferentes niveles de agua en el interior. Debe verter el agua en la menor cantidad posible de tubos de ensayo y obtener el resultado.

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

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

Como puede ver, los tubos de ensayo se separan con un solo espacio. Los tubos vacíos no deben mostrarse en la salida. Este es el código golf, por lo que gana el código con el menor número de bytes.

Casos de prueba: http://pastebin.com/BC0C0uii

¡Feliz golf!

Jacajack
fuente
¿Podemos también redistribuir el agua? Por ejemplo, ¿7 + 6 sería una salida válida para su ejemplo?
Martin Ender
@MartinEnder Debe usar la menor cantidad de tubos posible. Creo que eso es aceptable en este caso.
Jacajack
@StewieGriffin No he visto nada similar aquí todavía, así que si eso es un poco duplicado, lo siento
Jacajack
¿Se permite el espacio en blanco al final?
PurkkaKoodari
Mejor título - "Optimizador ASCII probetas bebés"
Optimizador

Respuestas:

4

Pyth, 48 45 44 bytes

jCssm+_B,*9\|_X+\_*8;ld\~*9;cUs*L/%2w\~_S8 8

Pruébalo en línea.

Imprime un único espacio final en cada línea.

PurkkaKoodari
fuente
4

JavaScript (ES6), 159148 bytes

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?`__`:`  `:`~~`)

Emite un salto de línea final. Editar: guardado 11 bytes con algo de ayuda de @Arnauld.

Neil
fuente
s.replace(/~~/g,(_,i)=>n+=9-i/s.indexOf`\n`|0,n=0)debería guardar 4 bytes. Es posible que desee inicializar n a -1 y usar n>>3y ~n&7^iguardar un byte más.
Arnauld
@Arnauld Gracias por la -1idea, pero pude mejorarla replace.
Neil
1
¡Agradable! Nunca me di cuenta de que 1/"\n"era verdad.
Arnauld
@Arnauld Bueno, solo fue un byte extra de guinda del pastel ...
Neil
3

Perl, 150 bytes

149 bytes de código + -nbandera.

$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$%

No explicaré todo el código, solo algunas cosas:
$l+=9-$.for/~~/gcuenta la cantidad de agua que hay en la entrada.
La segunda parte del código imprime la salida. La idea es colocar tantos tubos llenos como sea posible, y un último que contenga el agua que queda (si la hay). Así que el algoritmo es en 4 partes: imprime la primera línea de agua (la parte superior de los tubos): say"|~~| "x$v.($@="| | ")x$r. A continuación, imprimir partes vacías de los tubos hasta que alcanza el nivel de agua del último tubo: say$:=$@x$%for$l%8..6. A continuación, imprima el nivel en el que el agua del último tubo es: say$@x$v."|~~|"x$r. A continuación, imprima todos los restantes niveles "vacías": say$:for 2..$l%8;. Y, por último, imprimir el resultado final: say"|__| "x$%.
Los nombres de las variables dificultan la lectura ($% , $@, $:) pero permite palabras clave como xyfor para ser escrito después de la variable sin un espacio.

Para ejecutarlo:

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$%' <<< "|  | |  | |  | |  |
|  | |  | |  | |  |
|  | |~~| |  | |  |
|~~| |  | |  | |  |
|  | |  | |  | |  |
|  | |  | |  | |  |
|  | |  | |~~| |  |
|  | |  | |  | |  |
|__| |__| |__| |__| "

No estoy muy satisfecho con la duración de esta respuesta. Traté de sacar el máximo provecho de mi algoritmo, pero un enfoque diferente probablemente podría ser más corto. Intentaré trabajar en eso pronto.

Dada
fuente
@JamesHolderness Probé todos los casos de prueba (y volví a intentarlo ahora porque me hizo dudar) y me parece bien. "El último" es el que tiene 3 tubos: 2 con nivel de agua a 4 y 1 con agua a nivel 2, ¿verdad? Si es así, entonces lo probé y da el mismo resultado que el de pastbin
Dada
@JamesHolderness Oh, claro, ¡explica mucho! Gracias :)
Dada
3

Befunge, 144 138 bytes

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:#^_@

Pruébalo en línea!

Las primeras dos líneas procesan la entrada, básicamente ignorando todo excepto el primer carácter en cada tubo que podría ser un marcador de nivel. Tomamos el valor ASCII de ese personaje, dividimos por 2 y mod 2 (dándonos 1 o 0 dependiendo de si estamos en un marcador de nivel o no), lo multiplicamos por el número de fila (contando desde 8, dándonos así el valor de nivel para ese tubo) y agréguelo a un total acumulado.

La salida se maneja en las segundas dos líneas, esencialmente comenzando en el extremo derecho de la tercera línea. Primero calculamos el número de tubos tomando el nivel de agua total más 7 dividido por 8. Luego, al iterar sobre las filas de todos los tubos, calculamos el carácter que se mostrará dentro de un tubo específico ( t , contando hasta 0) para un fila dada ( r , cuenta atrás de 8 a 0) de la siguiente manera:

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

El char_type calculado es -1 para la fila inferior (la base del tubo), 0 para cualquier otra área que no sea un nivel de agua y 1 para el nivel de agua. Por lo tanto, se puede usar como una simple búsqueda en la tabla para que salga el carácter apropiado (puede ver esta tabla al comienzo de la línea 4).

James Holderness
fuente
2

Haskell, 186 bytes

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="|  | "

Ejemplo de uso:

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

Pone un espacio final en cada línea. Cómo funciona:

              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

El principal problema fue la falta de una función que cuente con qué frecuencia se produce una subcadena en una cadena. Hay counten Data.Text, pero la importación que lleva a un montón de conflictos de nombres que son demasiado caros para resolver.

nimi
fuente
1

Python, 261 bytes

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

Siento que hay algo que me falta. Además, si un montón de nuevas líneas son aceptables para la salida en blanco, podría perder algunos bytes. Toma entrada como '| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n|__| |__| |__|'.

nedla2004
fuente
1

Rubí , 139 bytes

(138 bytes de código más un byte para el -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)}

Pruébalo en línea!

Algunas explicaciones:

Este programa requiere el -ncambio.

n - Contador de agua.

b- Plantilla para la construcción de tubos; es igual"|__| "

i - Índice de línea actual durante la construcción del tubo.

gsub(/~~/){... }- Esto abusa gsubde contar simplemente el nivel del agua. gsuben realidad se expande a Kernel.gsub, que es equivalente a $_.gsub!. Esto manipula innecesariamente la línea actual ( $_); sin embargo, permite una asignación más concisa de b=... en [0,5]lugar de b=$_[0,5].

n=n+9-$.- Para medir el nivel del agua, la expresión usa la variable predefinida $., que lleva el número de línea de entrada actual . Esto me permitió perder la variable de bucle explícito.

b=gsub(/~~/){... }[0,5]- almacena en caché la parte inferior del tubo más a la izquierda como plantilla. (Se siente un poco como el patrón "Elefante en El Cairo" porque la línea de fondo gana).
Dado que el fondo del tubo nunca muestra agua, gsubno reemplazará nada cuando estemos allí; por lo tanto, al final, bsiempre es igual "|__| ".

END{... }- Se llama después de que se haya procesado toda la secuencia de entrada. Yo uso esta fase para construir los tubos objetivo.

i>0??\ :?~- es simplemente abreviatura de i > 0 ? " " : "~".

Actualización 1: Se agregaron detalles sobre las variables, el gsubtruco y la fase END{...}

Actualización 2: (± 0 bytes en general)

  • Usar en n||=0lugar de n=n||0 (-1 byte)
  • Tomó malus por -n (+1 byte)
Synoli
fuente
0

Python 3, 404 bytes

Este programa crea la salida prevista completa con los niveles de agua tanto en ASCII como en formatos numéricos.

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