Optimiser les tubes à essai ASCII

13

On vous donne un tas de tubes à essai ASCII, votre tâche est de réduire le nombre de tubes à essai utilisés.

Chaque tube à essai ressemble à ceci:

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

De toute évidence, ~~c'est le niveau de l'eau. Le tube à essai peut également être vide, auquel cas il n'y a pas de ~~caractères à l'intérieur. Un seul tube peut contenir jusqu'à 8 unités de niveau d'eau.

On vous donne un nombre fini de tubes à essai avec différents niveaux d'eau à l'intérieur. Vous devez verser l'eau dans le moins de tubes à essai possible et produire le résultat.

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

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

Comme vous pouvez le voir, les éprouvettes sont séparées par un seul espace. Les tubes vides ne doivent pas être affichés en sortie. Il s'agit de code golf, donc le code avec le moins d'octets gagne.

Cas de test: http://pastebin.com/BC0C0uii

Bon golf!

Jacajack
la source
Peut-on également redistribuer l'eau? Par exemple, 7 + 6 serait-il une sortie valide pour votre exemple?
Martin Ender
@MartinEnder Vous devez utiliser le moins de tubes possible. Je pense que c'est acceptable dans ce cas.
Jacajack
@StewieGriffin Je n'ai encore rien vu de similaire ici, donc si c'est un peu un doublon, je suis désolé
Jacajack
Les espaces de fin sont-ils autorisés?
PurkkaKoodari
Meilleur titre - "Optimizer ASCII test tube babies"
Optimizer

Réponses:

4

Pyth, 48 45 44 octets

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

Essayez-le en ligne.

Imprime un seul espace de fin sur chaque ligne.

PurkkaKoodari
la source
4

JavaScript (ES6), 159 148 octets

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

Sort un saut de ligne de fin. Edit: enregistré 11 octets avec l'aide de @Arnauld.

Neil
la source
s.replace(/~~/g,(_,i)=>n+=9-i/s.indexOf`\n`|0,n=0)devrait économiser 4 octets. Vous voudrez peut-être initialiser n à -1 à la place et utiliser n>>3et ~n&7^ienregistrer un octet supplémentaire.
Arnauld
@Arnauld Merci pour l' -1idée mais j'ai pu l'améliorer replace.
Neil
1
Agréable! Je n'ai jamais réalisé que 1/"\n"c'était vrai.
Arnauld
@Arnauld Eh bien, ce n'était qu'un octet supplémentaire de cerise sur le gâteau ...
Neil
3

Perl, 150 octets

149 octets de code + -nindicateur.

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

Je ne vais pas expliquer tout le code, juste quelques petites choses:
$l+=9-$.for/~~/gcompte la quantité d'eau dans l'entrée.
La deuxième partie du code imprime la sortie. L'idée est de mettre autant de tubes remplis que possible, et un dernier qui contient l'eau qui reste (le cas échéant). Donc , l'algorithme est en 4 parties: imprime la première ligne de l' eau (le haut de tubes) say"|~~| "x$v.($@="| | ")x$r. Ensuite, imprimez les parties vides de tubes jusqu'à ce qu'on atteigne le niveau d'eau du dernier tube: say$:=$@x$%for$l%8..6. Ensuite , imprimez le niveau où l'eau est la dernière du tube: say$@x$v."|~~|"x$r. Ensuite, imprimez tous les autres niveaux « vides »: say$:for 2..$l%8;. Et enfin, imprimer la ligne de fond: say"|__| "x$%.
Les noms de variables font qu'il est difficile à lire ( $%, $@, $:) mais permet des mots clés comme xetfor à écrire après la variable sans espace.

Pour l'exécuter:

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

Je ne suis pas très satisfait de la durée de cette réponse. J'ai essayé de tirer le meilleur parti de mon algorithme, mais une approche différente pourrait probablement être plus courte. J'essaierai d'y travailler bientôt.

Dada
la source
@JamesHolderness J'ai essayé tous les cas de test (et réessayé maintenant parce que vous m'aviez des doutes) et cela me semble bien. "Le dernier" est celui avec 3 tubes: 2 avec le niveau d'eau à 4, et 1 avec de l'eau au niveau 2, non? Si oui, alors je l'ai essayé et il donne la même sortie que celle sur pastbin
Dada
@JamesHolderness Oh oui, ça explique beaucoup de choses! Merci :)
Dada
3

Befunge, 144 138 octets

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

Essayez-le en ligne!

Les deux premières lignes traitent l'entrée, ignorant pratiquement tout sauf le premier caractère de chaque tube qui pourrait être un marqueur de niveau. Nous prenons la valeur ASCII de ce caractère, divisons par 2 et mod 2 (en nous donnant 1 ou 0 selon que nous sommes sur un marqueur de niveau ou non), multiplions cela par le numéro de ligne (en comptant à partir de 8, nous donnant ainsi la valeur de niveau pour ce tube), et l'ajouter à un total cumulé.

La sortie est gérée sur les deux secondes lignes, commençant essentiellement à l'extrême droite de la troisième ligne. Nous calculons d'abord le nombre de tubes en prenant le niveau d'eau total plus 7 divisé par 8. Ensuite, lors de l'itération sur les rangées de tous les tubes, nous calculons le caractère à afficher à l'intérieur d'un tube spécifique ( t , compte à rebours jusqu'à 0) pour un ligne donnée ( r , compte à rebours de 8 à 0) comme suit:

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

Le type de char calculé est -1 pour la ligne la plus basse (la base du tube), 0 pour toute autre zone qui n'est pas un niveau d'eau et 1 pour le niveau d'eau. Il peut donc être utilisé comme simple recherche de table pour le caractère approprié à afficher (vous pouvez voir ce tableau au début de la ligne 4).

James Holderness
la source
2

Haskell, 186 octets

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

Exemple d'utilisation:

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

Place un espace de fin sur chaque ligne. Comment ça fonctionne:

              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

La principale douleur était le manque d'une fonction qui compte la fréquence à laquelle une sous-chaîne se produit dans une chaîne. Il y counten a Data.Text, mais l'importer conduit à un tas de conflits de noms qui sont beaucoup trop chers à résoudre.

nimi
la source
1

Python, 261 octets

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

J'ai l'impression qu'il me manque quelque chose. De plus, si un tas de sauts de ligne sont acceptables pour la sortie vierge, je pourrais perdre quelques octets. Prend l'entrée comme '| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n|__| |__| |__|'.

nedla2004
la source
1

Rubis , 139 octets

(138 octets de code plus un octet pour le -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)}

Essayez-le en ligne!

Quelques explications:

Ce programme nécessite le -ncommutateur.

n - compteur d'eau.

b- Gabarit de construction de tubes; équivaut à"|__| "

i - Indice de ligne actuel pendant la construction du tube.

gsub(/~~/){}- Cela abuse gsubde simplement compter le niveau d'eau. gsubse développe en fait à Kernel.gsub, ce qui équivaut à $_.gsub!. Cela manipule inutilement la ligne actuelle ( $_); cependant, il permet une affectation plus concise de b=[0,5]au lieu de b=$_[0,5].

n=n+9-$.- Pour mesurer le niveau d'eau, l'expression utilise la variable prédéfinie $., qui porte le numéro de ligne d'entrée actuel . Cela m'a permis de perdre la variable de boucle explicite.

b=gsub(/~~/){}[0,5]- met en cache le bas du tube le plus à gauche comme modèle. (Pour moi, c'est un peu comme le motif «Éléphant au Caire» parce que la ligne du bas gagne.)
Puisque le fond du tube ne montre jamais d'eau, le gsubne remplacera rien quand nous y serons; donc au final, btoujours égal"|__| " .

END{}- Obtient appelé après que tout le flux d'entrée a été traité. J'utilise cette phase pour construire les tubes cibles.

i>0??\ :?~- est simplement raccourci pour i > 0 ? " " : "~".

Mise à jour 1: Ajout de détails sur les variables, la gsubruse et la phase END{}.

Mise à jour 2: (± 0 octets au total)

  • Utiliser n||=0au lieu de n=n||0 (-1 octet)
  • A pris du malus pour -n (+1 octet)
Synoli
la source
0

Python 3, 404 octets

Ce programme crée la sortie prévue complète avec les niveaux d'eau à la fois en format ASCII et numérique.

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