Optimieren Sie ASCII-Reagenzgläser

13

Sie erhalten eine Reihe von ASCII-Reagenzgläsern. Ihre Aufgabe ist es, die Anzahl der verwendeten Reagenzgläser zu reduzieren.

Jedes Reagenzglas sieht folgendermaßen aus:

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

Offensichtlich ~~ist der Wasserstand. Das Reagenzglas kann auch leer sein. In diesem Fall sind keine ~~Zeichen enthalten. Ein einzelnes Rohr kann bis zu 8 Wasserstandseinheiten enthalten.

Sie erhalten eine begrenzte Anzahl von Reagenzgläsern mit unterschiedlichen Wasserständen. Sie müssen das Wasser in möglichst wenigen Reagenzgläsern einfüllen und das Ergebnis ausgeben.

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

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

Wie Sie sehen, sind die Reagenzgläser durch ein einzelnes Leerzeichen getrennt. Leere Röhren sollten in der Ausgabe nicht angezeigt werden. Dies ist Codegolf, also gewinnt Code mit der geringsten Anzahl von Bytes.

Testfälle: http://pastebin.com/BC0C0uii

Viel Spaß beim Golfen!

Jacajack
quelle
Können wir das Wasser auch umverteilen? Wäre zB 7 + 6 eine gültige Ausgabe für Ihr Beispiel?
Martin Ender
@MartinEnder Sie sollten so wenig Röhren wie möglich verwenden. Ich denke, das ist in diesem Fall akzeptabel.
Jacajack
@StewieGriffin Ich habe hier noch nichts Ähnliches gesehen. Wenn es sich also um ein Duplikat handelt, tut es mir leid
Jacajack
Darf Leerzeichen nachgestellt werden?
PurkkaKoodari
Besserer Titel - "Optimizer ASCII Reagenzglas Babys"
Optimizer

Antworten:

4

Pyth, 48 45 44 Bytes

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

Probieren Sie es online aus.

Gibt in jeder Zeile ein einzelnes Leerzeichen aus.

PurkkaKoodari
quelle
4

JavaScript (ES6), 159 bis 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?`__`:`  `:`~~`)

Gibt einen nachgestellten Zeilenvorschub aus. Bearbeiten: 11 Bytes mit Hilfe von @Arnauld gespeichert.

Neil
quelle
s.replace(/~~/g,(_,i)=>n+=9-i/s.indexOf`\n`|0,n=0)sollte 4 Bytes sparen. Möglicherweise möchten Sie n stattdessen mit -1 initialisieren n>>3und ~n&7^iein weiteres Byte mit und speichern.
Arnauld
@Arnauld Danke für die -1Idee, aber ich konnte die replaceIdee verbessern .
Neil
1
Nett! Ich habe nie 1/"\n"bemerkt, dass es wahr ist.
Arnauld
@ Arnauld Nun, es war nur ein zusätzliches Byte Sahnehäubchen auf dem Kuchen ...
Neil
3

Perl, 150 Bytes

149 Byte Code + -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$%

Ich werde nicht den gesamten Code erklären, nur ein paar Dinge:
$l+=9-$.for/~~/gZählt, wie viel Wasser sich in der Eingabe befindet.
Der zweite Teil des Codes druckt die Ausgabe. Die Idee ist, so viele voll gefüllte Röhrchen wie möglich zu platzieren, und ein letztes, das das verbleibende Wasser enthält (falls vorhanden). So ist der Algorithmus , der in 4 Teilen ist: Die erste Zeile von Wasser (die Oberseite Röhrchen) say"|~~| "x$v.($@="| | ")x$r. Dann druckt leere Teile von Rohren , bis wir das Niveau von Wasser der letzten Röhre erreichen: say$:=$@x$%for$l%8..6. Dann drucken Sie die Ebene , wo das letzte Rohr Wasser: say$@x$v."|~~|"x$r. Dann drucken Sie alle verbleibenden „leer“ Ebenen: say$:for 2..$l%8;. Und schließlich druckt die untere Zeile: say"|__| "x$%.
Die Variablennamen machen es schwer zu lesen ( $%, $@, $:) , sondern ermöglicht Schlüsselwörter wie xundfor nach der Variablen ohne Leerzeichen zu schreiben.

Um es auszuführen:

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

Ich bin nicht sehr zufrieden damit, wie lange diese Antwort dauert. Ich habe versucht, das Beste aus meinem Algorithmus herauszuholen, aber ein anderer Ansatz könnte wahrscheinlich kürzer sein. Ich werde versuchen, bald daran zu arbeiten.

Dada
quelle
@ JamesHolderness Ich habe alle Testfälle ausprobiert (und jetzt erneut ausprobiert, weil Sie mich zweifeln ließen) und es scheint mir in Ordnung zu sein. "Der Letzte" ist der mit 3 Röhren: 2 mit Wasserstand bei 4 und 1 mit Wasser bei Level 2, richtig? Wenn ja, dann habe ich es versucht und es gibt die gleiche Ausgabe wie die auf Pastbin
Dada
@ JamesHolderness Oh, richtig, es erklärt viel! Danke :)
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:#^_@

Probieren Sie es online!

Die ersten beiden Zeilen verarbeiten die Eingabe und ignorieren im Grunde alles außer dem ersten Zeichen in jeder Röhre, das ein Level-Marker sein könnte. Wir nehmen den ASCII-Wert dieses Zeichens, dividieren durch 2 und mod 2 (geben uns 1 oder 0, je nachdem, ob wir uns auf einer Ebenenmarkierung befinden oder nicht), multiplizieren diesen mit der Zeilennummer (zählen von 8 herunter, was uns ergibt) den Pegelwert für diese Röhre) und addieren ihn zu einer laufenden Summe.

Die Ausgabe erfolgt in den zweiten beiden Zeilen, im Wesentlichen beginnend ganz rechts in der dritten Zeile. Wir berechnen zuerst die Anzahl der Röhren, indem wir den Gesamtwasserstand plus 7 geteilt durch 8 berechnen. Wenn wir dann über die Reihen aller Röhren iterieren, berechnen wir das Zeichen, das in einer bestimmten Röhre angezeigt werden soll ( t , Countdown bis 0) für a gegebene Zeile ( r , Countdown von 8 bis 0) wie folgt:

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

Der berechnete char_type ist -1 für die unterste Reihe (die Basis der Röhre), 0 für einen anderen Bereich, der kein Wasserstand ist, und 1 für den Wasserstand. Sie kann daher als einfache Tabellensuche für das auszugebende Zeichen verwendet werden (Sie können diese Tabelle am Anfang von Zeile 4 sehen).

James Holderness
quelle
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="|  | "

Anwendungsbeispiel:

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

Fügt in jede Zeile ein Leerzeichen ein. Wie es funktioniert:

              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

Der Hauptschmerz war das Fehlen einer Funktion, die zählt, wie oft eine Teilzeichenfolge in einer Zeichenfolge vorkommt. Es ist countin Data.Text, aber es führt zu einer Reihe von Namenskonflikten importieren , die sind viel zu teuer zu lösen.

nimi
quelle
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

Ich habe das Gefühl, dass mir etwas fehlt. Auch wenn eine Reihe von Zeilenumbrüchen für die leere Ausgabe möglich sind, kann ich einige Bytes verlieren. Nimmt Eingaben wie '| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n|__| |__| |__|'.

nedla2004
quelle
1

Rubin , 139 Bytes

(138 Byte Code plus ein Byte für die -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)}

Probieren Sie es online!

Ein paar Erklärungen:

Dieses Programm benötigt den -nSchalter.

n - Wasserzähler.

b- Vorlage für den Bau von Rohren; gleich"|__| "

i - Aktueller Linienindex während des Rohrbaus.

gsub(/~~/){}- Dies missbraucht, gsubum einfach den Wasserstand zu zählen. gsubErweitert sich tatsächlich zu Kernel.gsub, was äquivalent zu ist $_.gsub!. Dies manipuliert unnötigerweise die aktuelle Zeile ( $_); Dies ermöglicht jedoch eine präzisere Zuordnung von b=... [0,5]anstelle von b=$_[0,5].

n=n+9-$.- Um den Wasserstand zu messen, verwendet der Ausdruck die vordefinierte Variable $., die die aktuelle Eingabezeilennummer enthält . Dadurch konnte ich die explizite Schleifenvariable verlieren.

b=gsub(/~~/){}[0,5]- Cacht den unteren Rand der Tube ganz links als Vorlage. (Fühlt sich für mich ein bisschen wie das Muster "Elefant in Kairo" an, weil das Endergebnis gewinnt.)
Da der Boden der Röhre niemals Wasser anzeigt, ersetzt das gsubnichts, wenn wir dort sind. also am ende bimmer gleich "|__| ".

END{}- Wird aufgerufen, nachdem der gesamte Eingabestream verarbeitet wurde. In dieser Phase baue ich die Zielröhren.

i>0??\ :?~- ist einfach eine Abkürzung für i > 0 ? " " : "~".

Update 1: Details zu Variablen, den gsubTricks und den END{} -Phase .

Update 2: (± 0 Bytes insgesamt)

  • Verwenden Sie n||=0anstelle von n=n||0 (-1 Byte)
  • Nahm Malus für -n (+1 Byte)
Synoli
quelle
0

Python 3, 404 Bytes

Dieses Programm erstellt die vollständige beabsichtigte Ausgabe mit den Wasserständen sowohl im ASCII- als auch im Zahlenformat.

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
quelle