ASCIIテストチューブを最適化する


13

ASCIIテストチューブの束が与えられます。タスクは、使用するテストチューブの数を減らすことです。

各試験管は次のようになります。

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

明らかに、~~水位です。また、試験管を空にすることもできます~~。この場合、内部に文字はありません。1つのチューブには、最大8つの水位ユニットを含めることができます。

内部の水位が異なる有限数の試験管が与えられます。できるだけ少ない量の試験管に水を注ぎ、結果を出力する必要があります。

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

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

ご覧のとおり、試験管は単一のスペースで区切られています。空のチューブは出力に表示されません。これはコードゴルフであるため、バイト数が最小のコードが優先されます。

テストケース:http : //pastebin.com/BC0C0uii

ハッピーゴルフ!


水も再分配できますか?例えば、7 + 6はあなたの例にとって有効な出力でしょうか?
マーティンエンダー

@MartinEnderできるだけ少ない量のチューブを使用する必要があります。この場合、それは受け入れられると思います。
ジャカジャック16

ちょっとごめんなさい複製だということならば、私はそう、まだここに似た何かを見ていない@StewieGriffin
Jacajack

末尾の空白は許可されますか?
PurkkaKoodari 16

より良いタイトル-「オプティマイザー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?`__`:`  `:`~~`)

末尾の改行を出力します。編集:@Arnauldの助けを借りて11バイトを保存しました。


s.replace(/~~/g,(_,i)=>n+=9-i/s.indexOf`\n`|0,n=0)4バイトを節約する必要があります。代わりにnを-1に初期化し、さらにを使用n>>3~n&7^iてもう1バイトを保存することができます。
アーナルド

@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します。入力に含まれる水の量をカウントします。
コードの2番目の部分は出力を印刷します。考えは、できるだけ多くの完全に満たされたチューブと、残っている水がある場合はそれを含む最後のチューブを置くことです。そのため、アルゴリズムは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私はすべてのテストケースを試しました(そして、あなたが私を疑っていたので今再試行しました)そしてそれは私には問題ないようです。「最後の1つ」は、3つのチューブを持つものです。2つは水位が4で、1つは水位が2です。もしそうなら、私はそれを試してみました、それはpastbin上のものと同じ出力を与える
ダダ

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

オンラインでお試しください!

最初の2行は入力を処理し、基本的にレベルマーカーである可能性のある各チューブの最初の文字を除くすべてを無視します。その文字のASCII値を取得し、2とmod 2で除算し(レベルマーカー上にあるかどうかに応じて1または0を与えます)、それに行番号を掛けます(8からカウントダウンするため、そのチューブのレベル値)、それを積算合計に追加します。

出力は2番目の2行で処理され、基本的に3行目の右端から始まります。最初に合計水位に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

主な痛みは、サブストリングがストリング内で発生する頻度をカウントする機能の欠如でした。ありますcountData.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バイトのコードとのための1バイト-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バイト)

  • (-1バイト)のn||=0代わりに使用n=n||0
  • (+1バイト)のマルスを受けました-n

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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.