Оптимізуйте пробірки ASCII


13

Вам дають купу пробірок ASCII, ваше завдання - зменшити кількість використаних пробірок.

Кожна пробірка виглядає так:

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

Очевидно, ~~є рівень води. Пробірка також може бути порожньою, і в цьому випадку ~~символів всередині немає . Одинарна трубка може містити до 8 одиниць рівня води.

Вам надається обмежена кількість пробірок з різним рівнем води всередині. Ви повинні залити воду якомога меншою кількістю пробірок і вивести результат.

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

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

Як бачите, пробірки розділені одним простором. Порожні трубочки не повинні відображатись на виході. Це код гольфу, тому виграє код з найменшою кількістю байтів.

Тестові приклади: http://pastebin.com/BC0C0uii

Щасливого гольфу!


Чи можемо ми також перерозподілити воду? Наприклад, 7 + 6 буде допустимим результатом для вашого прикладу?
Мартін Ендер

@MartinEnder Ви повинні використовувати найменшу кількість трубок. Я думаю, що в цьому випадку це прийнятно.
Jacajack

@StewieGriffin я ще не бачив нічого подібного тут, тож якщо це якийсь дублікат, мені шкода
Jacajack

Чи дозволено пробіл пробілів?
PurkkaKoodari

Кращий заголовок - "Оптимізатор пробірки для немовлят ASCII"
Оптимізатор

Відповіді:



4

JavaScript (ES6), 159 148 байт

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

Виводить кінцеву лінію передачі. Редагувати: збережено 11 байт за допомогою довідки @Arnauld.


s.replace(/~~/g,(_,i)=>n+=9-i/s.indexOf`\n`|0,n=0)має зберегти 4 байти. Ви можете замість цього ініціалізувати n до -1 та використовувати n>>3і ~n&7^iзберегти ще один байт.
Арнольд

@Arnauld Дякую за -1ідею, але мені вдалося вдосконалити replaceідею.
Ніл

1
Приємно! Я ніколи не зрозумів, що 1/"\n"це правда.
Арнольд

@Arnauld Ну, це був лише зайвий байт глазурі на торті ...
Ніл

3

Perl, 150 байт

149 байт коду + -nпрапор.

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

Я не буду пояснювати весь код, лише декілька речей:
$l+=9-$.for/~~/gпідраховує, скільки води вводиться.
Друга частина коду друкує вихід. Ідея полягає в тому, щоб поставити якомога більше повністю заповнених трубок і останню, в якій міститься вода, що залишилася (якщо така є). Таким чином, алгоритм в 4 -х частин: друкує першу лінію води (вершина труб): say"|~~| "x$v.($@="| | ")x$r. Потім надрукуйте порожні частини труб до тих пір , поки не досягне рівня води останньої труби: say$:=$@x$%for$l%8..6. Потім роздрукуйте рівень , де остання труба води: say$@x$v."|~~|"x$r. Потім надрукувати все, що залишилися «порожні» рівні: say$:for 2..$l%8;. І , нарешті, друк в нижньому рядку: say"|__| "x$%.
Імена змінних роблять його важко читати ( $%, $@, $:) , але дозволяє ключові слова , як xіfor записувати після змінної без пробілу.

Щоб запустити його:

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

Я не дуже задоволений тим, як триває ця відповідь. Я намагався зробити найкраще з мого алгоритму, але інший підхід, можливо, міг бути коротшим. Я спробую скоріше попрацювати над цим.


@JamesHolderness Я пробував усі тестові справи (і повторно намагався зараз, тому що ви сумнівались), і мені це здається прекрасним. "Останній" - це той, який має 3 трубки: 2 з рівнем води на 4, і 1 з водою на рівні 2, правда? Якщо так, то я спробував це, і він дає той самий результат, що і той, що на пастбіні
Dada

@JamesHolderness О так, це багато що пояснює! Дякую :)
Дада

3

Befunge, 144 138 байт

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

Спробуйте в Інтернеті!

Перші два рядки обробляють введення, в основному ігноруючи все, крім першого символу в кожній трубці, який може бути маркером рівня. Ми беремо значення ASCII цього символу, ділимо на 2 і mod 2 (даючи нам 1 або 0 залежно від того, ми знаходимося на рівні маркера чи ні), помножимо це на номер рядка (відлік від 8, таким чином, даючи нам значення рівня для цієї трубки) і додайте її до поточної загальної суми.

Висновок обробляється в двох других рядках, по суті починаючи з правого краю третього рядка. Спочатку обчислюємо кількість трубок, беручи загальний рівень води плюс 7, поділене на 8. Потім, перебираючи рядки всіх трубок, ми обчислюємо символ, який відображатиметься всередині певної трубки ( t , рахуючи до 0) для a заданий рядок ( r , відлік від 8 до 0) наступним чином:

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

Розрахунковий тип char_ дорівнює -1 для самого нижнього ряду (основа трубки), 0 для будь-якої іншої області, яка не є рівнем води, і 1 для рівня води. Таким чином, він може бути використаний як простий пошук таблиці для виведення відповідного символу (ви можете побачити цю таблицю на початку рядка 4).


2

Haskell, 186 байт

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

Приклад використання:

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

Розміщує пробіл у кожному рядку. Як це працює:

              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

Основним болем була відсутність функції, яка підраховує, як часто підрядка трапляється в рядку. Там же countв Data.Text, але імпортування призводить до зв'язці конфліктів імен, які дуже дорогі , щоб вирішити.


1

Пітон, 261 байт

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

Я відчуваю, що чогось мені не вистачає. Крім того, якщо купа нових рядків буде придатною для пустого виводу, я можу втратити кілька байт. Приймає вхід як '| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n|__| |__| |__|'.


1

Рубін , 139 байт

(138 байт коду плюс один байт для -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)}

Спробуйте в Інтернеті!

Кілька пояснень:

Ця програма вимагає -nкомутатора.

n - лічильник води.

b- шаблон для побудови трубок; дорівнює"|__| "

i - Поточний індекс лінії під час будівництва труб.

gsub(/~~/){}- Це зловживання gsubпросто порахувати рівень води. gsubнасправді розширюється до Kernel.gsub, що еквівалентно $_.gsub!. Це зайво маніпулює поточним рядком ( $_); однак це дозволяє більш стисло призначити b=[0,5]замість b=$_[0,5].

n=n+9-$.- Для вимірювання рівня води в виразі використовується заздалегідь визначена змінна $., яка несе поточний номер вхідного рядка . Це дозволило мені втратити явну змінну циклу.

b=gsub(/~~/){}[0,5]- зберігає нижню частину крайньої лівої трубки як шаблон. (Мені трохи схоже на шаблон "Слон в Каїрі", тому що нижня лінія перемагає.)
Оскільки в нижній частині трубки ніколи не з’являється вода, gsubвона нічого не замінить, коли ми там; тому в підсумку bзавжди дорівнює "|__| ".

END{}- отримує виклик після обробки всього вхідного потоку. Я використовую цю фазу для побудови цільових труб.

i>0??\ :?~- це просто короткий потік для i > 0 ? " " : "~".

Оновлення 1: Додано відомості про змінні, gsubхитрість та END{}фазу.

Оновлення 2: (усього ± 0 байт)

  • Використовувати n||=0замість n=n||0 (-1 байт)
  • Взяв малус за -n (+1 байт)

0

Пітон 3, 404 байти

Ця програма створює повний запланований вихід з рівнями води як у форматах ASCII, так і в численних форматах.

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.