Zoptymalizuj probówki ASCII

13

Dostajesz kilka probówek ASCII, Twoim zadaniem jest zmniejszenie liczby używanych probówek.

Każda probówka wygląda następująco:

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

Oczywiście ~~jest poziom wody. Probówka może być również pusta, w którym to przypadku nie ma żadnych ~~znaków. Pojedyncza rurka może zawierać do 8 jednostek poziomu wody.

Otrzymujesz skończoną liczbę probówek z różnymi poziomami wody w środku. Musisz wlać wodę do możliwie najmniejszej ilości probówek i wyprowadzić wynik.

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

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

Jak widać, probówki są oddzielone pojedynczą spacją. Puste probówki nie powinny być pokazywane na wyjściu. To jest kod golfowy, więc wygrywa kod z najmniejszą liczbą bajtów.

Przypadki testowe: http://pastebin.com/BC0C0uii

Miłej gry w golfa!

Jacajack
źródło
Czy możemy również rozprowadzać wodę? Np. Czy 7 + 6 byłoby prawidłowym wyjściem dla twojego przykładu?
Martin Ender,
@MartinEnder Powinieneś używać możliwie najmniejszej liczby rurek. Myślę, że w tym przypadku jest to dopuszczalne.
Jacajack,
@StewieGriffin Nie widziałem jeszcze czegoś podobnego, więc jeśli to trochę duplikat, przepraszam
Jacajack
Czy dozwolone są końcowe białe znaki?
PurkkaKoodari,
Lepszy tytuł - „Dzieci z probówki Optimizer ASCII”
Optimizer

Odpowiedzi:

4

Pyth, 48 45 44 bajtów

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

Wypróbuj online.

Drukuje pojedyncze końcowe miejsce w każdej linii.

PurkkaKoodari
źródło
4

JavaScript (ES6), 159 148 bajtów

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

Wysyła końcowy kanał. Edycja: Zapisano 11 bajtów przy pewnej pomocy @Arnauld.

Neil
źródło
s.replace(/~~/g,(_,i)=>n+=9-i/s.indexOf`\n`|0,n=0)powinien zaoszczędzić 4 bajty. Zamiast tego możesz zainicjować n do -1 i użyć n>>3i ~n&7^izapisać jeszcze jeden bajt.
Arnauld,
@Arnauld Dzięki za -1pomysł, ale udało mi się go ulepszyć replace.
Neil
1
Ładny! Nigdy nie zdawałem sobie sprawy, że 1/"\n"to prawda.
Arnauld,
@Arnauld Cóż, to był tylko dodatkowy bajt polewy na torcie ...
Neil
3

Perl, 150 bajtów

149 bajtów kodu + -nflaga.

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

Nie wyjaśnię całego kodu, tylko kilka rzeczy:
$l+=9-$.for/~~/gliczy, ile wody jest na wejściu.
Druga część kodu drukuje dane wyjściowe. Chodzi o to, aby umieścić jak najwięcej w pełni wypełnionych probówek, a ostatnia zawiera wodę, która pozostała (jeśli w ogóle). Tak algorytm jest na 4 części: drukuje pierwszej linii wody (w górnej części rurki) say"|~~| "x$v.($@="| | ")x$r. Następnie wydrukować puste fragmenty rur, aż osiągnie poziom wody w ostatniej rury: say$:=$@x$%for$l%8..6. Następnie wydrukować poziom, gdzie woda ostatnia rura jest: say$@x$v."|~~|"x$r. Następnie wydrukować wszystkie pozostałe „pustych” poziomy: say$:for 2..$l%8;. I wreszcie, wydrukować dolnej linii: say"|__| "x$%.
Nazwy zmiennych sprawiają, że trudno odczytać ( $%, $@, $:), ale pozwala na słowa kluczowe, jak xifor do zapisania po zmiennej bez spacji.

Aby uruchomić:

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

Nie jestem bardzo zadowolony z tego, jak długo trwa ta odpowiedź. Próbowałem jak najlepiej wykorzystać mój algorytm, ale inne podejście może być prawdopodobnie krótsze. Spróbuję wkrótce nad tym popracować.

Dada
źródło
@JamesHolderness Wypróbowałem wszystkie przypadki testowe (i ponownie spróbowałem teraz, ponieważ masz wątpliwości) i wydaje mi się to w porządku. „Ostatni” to ten z 3 rurkami: 2 z poziomem wody na poziomie 4 i 1 z wodą na poziomie 2, prawda? Jeśli tak, to spróbowałem i daje to ten sam wynik, co ten na pastbinie
Dada,
@JamesHolderness No tak, to wiele wyjaśnia! Dzięki :)
Dada,
3

Befunge, 144 138 bajtów

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

Wypróbuj online!

Pierwsze dwa wiersze przetwarzają dane wejściowe, w zasadzie ignorując wszystko oprócz pierwszego znaku w każdej tubie, który może być znacznikiem poziomu. Bierzemy wartość ASCII tego znaku, dzielimy przez 2 i mod 2 (dając nam 1 lub 0 w zależności od tego, czy jesteśmy na znaczniku poziomu, czy nie), mnożymy to przez liczbę wierszy (odliczając od 8, dając nam w ten sposób wartość poziomu dla tej rurki) i dodaj ją do bieżącej sumy.

Dane wyjściowe są obsługiwane w dwóch kolejnych wierszach, zaczynając zasadniczo po prawej stronie trzeciego wiersza. Najpierw obliczamy liczbę rurek, biorąc całkowity poziom wody plus 7 podzielone przez 8. Następnie, podczas iteracji nad rzędami wszystkich rurek, obliczamy postać wyświetlaną w określonej rurce ( t , odliczając do 0) dla dany wiersz ( r , odliczanie od 8 do 0) w następujący sposób:

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

Obliczony typ char wynosi -1 dla najniższego rzędu (podstawy rury), 0 dla każdego innego obszaru, który nie jest poziomem wody, i 1 dla poziomu wody. Można go zatem wykorzystać jako proste wyszukiwanie w tabeli odpowiedniego znaku wyjściowego (można zobaczyć tę tabelę na początku wiersza 4).

James Holderness
źródło
2

Haskell, 186 bajtów

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

Przykład użycia:

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

Umieszcza końcowe miejsce w każdej linii. Jak to działa:

              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

Głównym bólem był brak funkcji, która liczy, jak często podciąg występuje w ciągu. Jest countw Data.Text, ale to prowadzi do importowania bandą konfliktów nazw, które są zbyt drogie, aby rozwiązać.

nimi
źródło
1

Python, 261 bajtów

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

Czuję, że czegoś mi brakuje. Ponadto, jeśli kilka pustych wierszy jest akceptowalnych dla pustych danych wyjściowych, mogę stracić niektóre bajty. Przyjmuje dane wejściowe jak '| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n|__| |__| |__|'.

nedla2004
źródło
1

Rubin , 139 bajtów

(138 bajtów kodu plus jeden bajt dla -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)}

Wypróbuj online!

Kilka wyjaśnień:

Ten program wymaga -nprzełącznika.

n - licznik wody.

b- Szablon do konstruowania rur; równa się"|__| "

i - Aktualny wskaźnik linii podczas budowy rury.

gsub(/~~/){}- To nadużycie, gsubaby po prostu policzyć poziom wody. gsubfaktycznie rozwija się do Kernel.gsub, co jest równoważne z $_.gsub!. To niepotrzebnie manipuluje bieżącą linią ( $_); pozwala jednak na bardziej zwięzłe przypisanie b=[0,5]zamiast b=$_[0,5].

n=n+9-$.- Aby zmierzyć poziom wody, wyrażenie używa wstępnie zdefiniowanej zmiennej $., która przenosi bieżący numer linii wejściowej . To pozwoliło mi stracić jawną zmienną pętli.

b=gsub(/~~/){}[0,5]- buforuje spód dolnej skrajnej lewej rurki jako szablon. (Czuję się trochę jak wzór „Elephant in Cairo”, ponieważ wygrywa dolna linia.)
Ponieważ dno rurki nigdy nie pokazuje wody, gsubnic nie zastąpi, gdy będziemy na miejscu; dlatego ostatecznie bzawsze jest równy "|__| ".

END{}- Pobiera wywołania po przetworzeniu całego strumienia wejściowego. Używam tej fazy do konstruowania docelowych rur.

i>0??\ :?~- jest po prostu skrótem i > 0 ? " " : "~".

Aktualizacja 1: Dodano szczegóły dotyczące zmiennych, gsuboszustwa i fazy END{}.

Aktualizacja 2: (± 0 bajtów ogółem)

  • Użyj n||=0zamiast n=n||0 (-1 bajt)
  • Wzięto błąd dla -n (+1 bajt)
Synoli
źródło
0

Python 3, 404 bajty

Ten program tworzy pełne zamierzone dane wyjściowe z poziomami wody zarówno w formacie ASCII, jak i liczbowym.

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
źródło