Optimalkan tabung reaksi ASCII

13

Anda diberi banyak tabung reaksi ASCII, tugas Anda adalah mengurangi jumlah tabung reaksi yang digunakan.

Setiap tabung reaksi terlihat seperti ini:

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

Jelas, ~~adalah ketinggian air. Tabung reaksi juga bisa kosong, dalam hal ini tidak ada ~~karakter di dalamnya. Tabung tunggal dapat berisi hingga 8 unit level air.

Anda diberi jumlah terbatas tabung reaksi dengan level air yang berbeda di dalamnya. Anda harus menuangkan air dalam jumlah yang paling mungkin dari tabung reaksi, dan mengeluarkan hasilnya.

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

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

Seperti yang Anda lihat, tabung reaksi dipisahkan dengan ruang tunggal. Tabung kosong tidak boleh ditampilkan dalam output. Ini adalah kode golf, jadi kode dengan jumlah byte terkecil menang.

Uji kasus: http://pastebin.com/BC0C0uii

Selamat bermain golf!

Jacajack
sumber
Bisakah kita juga mendistribusikan ulang air? Misalnya, apakah 7 + 6 akan menjadi output yang valid untuk contoh Anda?
Martin Ender
@ MartinEnder Anda harus menggunakan tabung sesedikit mungkin. Saya pikir itu dapat diterima dalam kasus ini.
Jacajack
@StewieGriffin Saya belum melihat yang serupa di sini, jadi Jika itu agak duplikat, saya minta maaf
Jacajack
Apakah trailing whitespace diizinkan?
PurkkaKoodari
Judul yang lebih baik - "Pengoptimal ASCII bayi tabung"
Pengoptimal

Jawaban:

4

Pyth, 48 45 44 byte

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

Cobalah online.

Mencetak satu spasi tambahan di setiap baris.

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

Menghasilkan linefeed tambahan. Sunting: Disimpan 11 byte dengan bantuan dari @Arnauld.

Neil
sumber
s.replace(/~~/g,(_,i)=>n+=9-i/s.indexOf`\n`|0,n=0)harus menyimpan 4 byte. Anda mungkin ingin menginisialisasi n ke -1 dan menggunakan n>>3dan ~n&7^imenyimpan satu byte lagi.
Arnauld
@Arnauld Terima kasih atas -1idenya tetapi saya dapat memperbaiki replaceidenya.
Neil
1
Bagus! Saya tidak pernah menyadari 1/"\n"kebenaran.
Arnauld
@Arnauld Yah, itu hanya satu byte tambahan dari icing pada kue ...
Neil
3

Perl, 150 byte

149 byte kode + -nbendera.

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

Saya tidak akan menjelaskan semua kode, hanya beberapa hal:
$l+=9-$.for/~~/gmenghitung berapa banyak air dalam input.
Bagian kedua dari kode mencetak output. Idenya adalah untuk menempatkan tabung terisi penuh sebanyak mungkin, dan yang terakhir yang berisi air yang tersisa (jika ada). Jadi algoritma adalah dalam 4 bagian: mencetak baris pertama dari air (bagian atas tabung): say"|~~| "x$v.($@="| | ")x$r. Kemudian, mencetak bagian kosong dari tabung sampai kita mencapai tingkat air dari tabung terakhir: say$:=$@x$%for$l%8..6. Kemudian mencetak tingkat di mana air tabung terakhir adalah: say$@x$v."|~~|"x$r. Kemudian, mencetak semua yang tersisa "kosong" tingkat yang: say$:for 2..$l%8;. Dan akhirnya, mencetak Intinya: say"|__| "x$%.
Nama variabel membuat sulit untuk membaca ( $%, $@, $:) tapi memungkinkan untuk kata kunci seperti xdanfor ditulis setelah variabel tanpa spasi.

Untuk menjalankannya:

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

Saya tidak puas dengan berapa lama jawaban ini. Saya mencoba membuat yang terbaik dari algoritma saya, tetapi pendekatan yang berbeda mungkin bisa lebih pendek. Saya akan mencoba mengatasinya segera.

Dada
sumber
@ JamesHolderness Saya sudah mencoba semua test case (dan coba lagi sekarang karena kamu membuat saya ragu) dan sepertinya baik untuk saya. "Yang terakhir" adalah yang dengan 3 tabung: 2 dengan permukaan air pada 4, dan 1 dengan air pada tingkat 2, kan? Jika demikian, maka saya mencobanya dan memberikan hasil yang sama dengan yang ada di pastbin
Dada
@ JamesHolderness Oh benar, itu menjelaskan banyak hal! Terima kasih :)
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:#^_@

Cobalah online!

Dua baris pertama memproses input, pada dasarnya mengabaikan segalanya kecuali karakter pertama di setiap tabung yang mungkin menjadi penanda level. Kami mengambil nilai ASCII dari karakter itu, dibagi dengan 2 dan mod 2 (memberi kami 1 atau 0 tergantung pada apakah kita berada pada penanda level atau tidak), kalikan dengan nomor baris (menghitung mundur dari 8, sehingga memberi kami nilai level untuk tabung itu), dan menambahkannya ke total yang berjalan.

Output ditangani pada dua baris kedua, pada dasarnya dimulai pada ujung kanan dari baris ketiga. Kami pertama menghitung jumlah tabung dengan mengambil level air total ditambah 7 dibagi dengan 8. Kemudian ketika iterasi di atas baris semua tabung, kami menghitung karakter untuk ditampilkan di dalam tabung tertentu ( t , menghitung mundur ke 0) untuk diberikan baris ( r , menghitung mundur dari 8 ke 0) sebagai berikut:

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

Char_type yang dihitung adalah -1 untuk baris paling bawah (dasar tabung), 0 untuk area lain yang bukan permukaan air, dan 1 untuk permukaan air. Dengan demikian dapat digunakan sebagai pencarian tabel sederhana untuk karakter yang sesuai untuk output (Anda dapat melihat tabel ini di awal baris 4).

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

Contoh penggunaan:

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

Beri spasi tambahan di setiap baris. Bagaimana itu bekerja:

              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

Nyeri utama adalah kurangnya fungsi yang menghitung seberapa sering substring terjadi dalam string. Ada countdi Data.Text, tetapi mengimpornya mengarah ke banyak konflik nama yang terlalu mahal untuk diselesaikan.

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

Saya merasa ada sesuatu yang hilang. Juga, jika banyak baris baru dapat diterima untuk output kosong, saya bisa kehilangan beberapa byte. Mengambil input seperti '| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n|__| |__| |__|'.

nedla2004
sumber
1

Ruby , 139 byte

(138 byte kode ditambah satu byte untuk -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)}

Cobalah online!

Beberapa penjelasan:

Program ini membutuhkan -nsakelar.

n - penghitung air.

b- Templat untuk membuat tabung; sama dengan"|__| "

i - Indeks garis saat ini selama konstruksi tabung.

gsub(/~~/){... }- Penyalahgunaan ini gsubhanya untuk menghitung ketinggian air. gsubsebenarnya mengembang Kernel.gsub, yang setara dengan $_.gsub!. Ini tidak perlu memanipulasi baris saat ini ( $_); namun, ini memungkinkan untuk penugasan yang lebih singkat dari b=... [0,5]alih-alih b=$_[0,5].

n=n+9-$.- Untuk mengukur ketinggian air, ekspresi menggunakan variabel yang ditentukan sebelumnya $., yang membawa nomor saluran input saat ini . Ini memungkinkan saya kehilangan variabel loop eksplisit.

b=gsub(/~~/){... }[0,5]- cache bagian bawah tabung paling kiri sebagai templat. (Terasa sedikit seperti pola "Gajah di Kairo" bagi saya karena garis bawah menang.)
Karena bagian bawah tabung tidak pernah menunjukkan air, makagsub tidak akan menggantikan apa pun ketika kita berada di sana; oleh karena itu pada akhirnya, bselalu sama "|__| ".

END{...} - Mendapat panggilan setelah seluruh aliran input diproses. Saya menggunakan fase ini untuk membangun tabung target.

i>0??\ :?~ - hanya tangan pendek untuk i > 0 ? " " : "~" .

Pembaruan 1: Menambahkan detail pada variabel, thegsub tipu daya dan END{... }fase.

Pembaruan 2: (± 0 byte secara keseluruhan)

  • Menggunakan n||=0 alih-alih n=n||0 (-1 byte)
  • Mengambil malus untuk -n (+1 byte)
Synoli
sumber
0

Python 3, 404 byte

Program ini menciptakan hasil yang diinginkan penuh dengan ketinggian air dalam format ASCII dan angka.

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
sumber