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
,但在导入它导致了一堆名字冲突,这都太昂贵的决心。