Оптимизировать пробирки 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, верно? Если так, то я попробовал это, и он выдает тот же результат, что и на pastbin
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) для заданный ряд ( r , считающий от 8 до 0) следующим образом:

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

Рассчитываются char_type -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

Python, 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

Python 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.