仕様から長方形を生成する


14

前書き

この課題は、2Dパターンマッチング言語であるGrimeに触発されました。基本的に、文字の2次元グリッドを記述する「グラマー」が与えられ、あなたの仕事はグラマーに従ってグリッドを生成することです。さらに、グリッドは特定の弱い意味で可能な限り小さくする必要があります。

入力

入力は、小文字のASCII文字と記号|およびを含む文字列-です。簡単にするために、入力には繰り返し小文字が含まれていません。文字列は、文字の長方形グリッドのクラスの仕様であり、次のようにスタックを使用して左から右に解析されます。

  • 小文字の文字を考えるとc、スタックにプッシュしm×nた文字のグリッドをc任意のため、m, n ≥ 1
  • パイプが与えられたら、|2つのグリッドAをポップBし、スタックから(B一番上にありました)、AB連結Bして得られたグリッドをの右側にプッシュしAます。これには、AそれBが必要で、同じ高さがあります。
  • ハイフンを指定すると-、2つのグリッドABスタックから(上にBあった)ポップし、A/B連結Bして得られたグリッドをの一番下にプッシュしAます。これは、ことが必要AB等しい幅を持っています。

解析プロセス(文字ごとに異なる場合があります)の一部の選択mおよびn作成中に、入力仕様がスタックの最後に残っている長方形を正しく記述することが保証されます。

出力

出力は、入力で指定された文字の長方形のグリッドです。行または列を削除するとグリッドが無効になるという意味で、グリッドは最小限でなければなりません。改行で区切られた文字列(末尾の改行の有無にかかわらず)、2Dの文字配列、または文字列の配列のうち、最も便利な形式を返すことができます。

上記のとおりに入力を処理する必要はありません。唯一重要なことは、出力が正しいことです。

仕様を検討する

par-s||e-

まず、プッシュすることを選択した1×2の矩形をp、と1×1の長方形ar(この理由は、後に明らかであろう)。その後、我々はポップar長方形を、その垂直連結を押します

a
r

次に、の1×2長方形をプッシュし、sそれと上の長方形をポップし、それらの水平連結をプッシュします

as
rs

次に、その四角形と四角形をポップしp、それらの連結をプッシュします

pas
prs

最後に、の3×1長方形をプッシュし、eそれと上の長方形をポップし、垂直連結をプッシュします

pas
prs
eee

これは、プログラムの出力、または少なくとも1つの可能性です。ただし、

ppas
ppas
pprs
eeee

また、仕様によって生成されます。多くの行と列を削除できるため、有効な出力ではありません。

より微妙な例として、考慮してください

co|m|p|il|e|r|-

この仕様は長方形を生成します

comp
iler

これは有効な出力です。ただし、それはまた生成します

commp
iiler

無効にすることなく単一の行または列を削除することはできないため、これも有効です。

ルール

完全なプログラムまたは機能を提供できます。最小のバイトカウントが優先され、標準の抜け穴は許可されません。

追加のテストケース

これらを使用してプログラムをテストできます。

Input:
a
Output:
a

Input:
co|mp|l|-ex|i|f|-y|
Example output:
cccoy
mplly
exify

Input:
ja-r|g-o|ni-|ze|d-|
Example output:
jronze
arondd
ggoidd

Input:
un|co|p-yr|i|gh-t-ab|-|le-||-
Example output:
unnnnnnn
coyriggl
ppyrihhe
ppyritte
ppyriabe

nとmはどこから来たのですか?
seequ

静的にすることも、何らかの形式の入力にする必要がありますか?
seequ

@Sieg nmは非決定的に選択されます。それらに適した値が存在することは保証されていますが、それらを見つけるのはプログラムの仕事です。
ズガルブ

実際には、それらが何であるかを定義しません。
-seequ

un|co|p-|yr|i|gh--t-ab|-|le-||-有効にすることは不可能です。最後-のアリティは2ですが、スタックには要素が1つしかありません。
orlp

回答:


6

K、 123 110バイト

cardboard_boxのソリューションにも同様のアプローチを使用しました。

r:{y,x#,*|y};h:{t:(#x)|#y;r[t-#x;x],'r[t-#y]y};a:{(,x .|2#y),2_ y};*(){(a[{+h[+x;+y]}]x;a[h]x;(,,y),x)"-|"?y}/

このプログラムは、一連のヘルパー定義と、それに続く正しい引数として文字列をとる暗黙の関数です。読みやすくするために再フォーマットし、最終関数をf次のように割り当てます。

r: {y,x#,*|y};                           / repeat last row x times
h: {t:(#x)|#y;r[t-#x;x],'r[t-#y;y]};     / append horizontal
v: {+h[+x;+y]};                          / append vertical
a: {(,x[y@1;y@0]),2_ y};                 / pop two values, concat

f: *(){:[y="-";a[v;x]; y="|";a[h;x]; (,,y),x]}/;

使用例:

  f "ja-r|g-o|ni-|ze|d-|"
("jronze"
 "aroidd"
 "ggoidd")

コナを使用してテストしたが、それはまたに動作します[OK]を、あなたが交換した場合:の定義にf持つ$- k5が「指揮」の構文を変更しました。

重要な点は、垂直方向の追加を行うことは、両方の行列の転置の水平方向の追加の転置であることを認識することです。(定義を参照v)いくつかのキャラクターをあちこち絞り出す余地はまだあると思います。誰かがより詳細な説明に興味があるなら、私はそれを提供することができます。

編集:

このエントリの上部にあるプログラムを更新しました。ゴルフされていないバージョン:

r: {y,x#,*|y};                           / repeat row x times
h: {t:(#x)|#y;r[t-#x;x],'r[t-#y;y]};     / append horizontal
v: {+h[+x;+y]};                          / append vertical
a: {(,x .|2#y),2_ y};                    / apply a concat
f: *(){(a[v]x;a[h]x;(,,y),x)"-|"?y}/;

注目すべき長さの最適化には、「ドット適用」の使用a、「cond」のリストインデックス付けfへの置き換え(非効率的ですが短い)、グループ化で許可さa[b;c]れたa[b]c場所へのフォームの用語の置き換えが含まれます。私はもう「cond」やk3とk5で異なるプリミティブを使用していないので、このバージョンは変更なしでoKで動作します。


賞金を獲得しておめでとうございます!
ズガルブ

ありがとう!これは興味深い問題であり、Kに非常に好評でした。比較のためにJまたはAPLでの試みを見るのは興味深いことでした。
-JohnE

4

プロローグ、539バイト

:-lib(ic).
:-lib(util).
b(A,B,C):-between(A,B,C).
g(S):-string_list(S,L),p(L,[]).
w(h(L,R):_:_,I,J):-w(L,I,J);L=_:W:_,X is I-W,w(R,X,J).
w(v(U,D):_:_,I,J):-w(U,I,J);U=_:_:H,Y is J-H,w(D,I,Y).
w(f(C):W:H,I,J):-b(1,W,I),b(1,H,J),char_code(S,C),put_char(S).
p([],[S]):-term_variables(S,V),S=_:X:Y,labeling(V),!,b(1,Y,J),(b(1,X,I),w(S,I,J);nl),fail.
p([124|T],[Q,Z|R]):-!,Q=_:WA:H,Z=_:WB:H,W #= WA+WB,p(T,[h(Z,Q):W:H|R]).
p([45|T],[Q,Z|R]):-!,Q=_:W:HA,Z=_:W:HB,H #= HA+HB,p(T,[v(Z,Q):W:H|R]).
p([C|T],R):-!,[H,W] #:: 1..100,p(T,[f(C):W:H|R]).

説明

predicate gで開始します。これは文字列を受け取り、文字のリストとして変換pし、2番目の引数として空のスタックで(解析)述語を呼び出します。

述部pは、適切に変更されたスタックで再帰的にそれ自体を呼び出します([H|T]構造化パターンとコンストラクターパターンを探します)。入力リストが空である基本ケースで呼び出されるとp、スタックの一意の要素を出力します。この時点でスタックの要素が1つまたは複数の場合、空の入力文字列、不正な入力文字列、またはバグ(空の文字列がある場合、述語は失敗します(PrologによるとNo)が、何も出力されません。空の文字列については何も印刷しないでください)。

解く

スタックには、で示される構築された長方形の説明が含まれますS:W:H。ここSで、長方形の記号表現、Wその幅とH高さ(注、というファンクターを持つタプルのA:B構文シュガーです。:(A,B)タプルを:持つよりも書く方が短いです)プレフィックス表記付き)。

Aし、Bサブ長方形の仕様、Sのいずれかになります。

  • h(A,B) :AとBの水平連結
  • v(A,B) :AとBの垂直連結
  • f(C) :Cで埋めます。Cは文字コードです

グリッドの幅と高さは制約プログラミング変数です。垂直(または水平)連結中、操作された長方形の幅(または高さ)は統一されますが、結果の高さ(または幅)は以下の合計に制約されます。各サブグリッドの高さ(または幅)。

プロセスの最後のラベル付けステップでは、可能な限り最小の値を使用して、制約を尊重しながら変数をインスタンス化します(これは、解が試行される順序のプロパティです)。

他の回答で行われたのと同じ理由付けを使用して、制約なしに短い回答を得たかもしれませんが、これは遅すぎます。

また、変数のデフォルトドメインがに設定されているため1..100、グリッドの可能なサイズには制限があることに注意してください。必要に応じて上限を変更できます。これがパフォーマンスに与える影響は、特定のソリューションがソリューションを認めないことを判断するのに時間かかる可能性があることです。制約は指数関数的検索を大幅に削減する可能性が高いため、「可能」と言いました。拒否するのが難しい/コストのかかる入力文字列を見つけたら、共有してください。

印刷

以下のようなものがあるため、印刷部分は興味深いレイキャスティング構造上のアルゴリズムは:I反復点から得られたグリッドの各セル、オーバー(1,1)(W,H)と呼んでw述語がメインツリーにグリッドの内容を印刷するために、時この場所(もちろん、各行の処理後に改行が印刷されます)。

ではw、位置は現在のグリッドに相対的です(ルートグリッドは絶対座標を定義します)。

h(A,B)ポイント(X,Y)で構造を印刷するとき、私は無条件に両方のブランチに印刷します:

  • Aポイントのグリッド内(X,Y)、および
  • グリッドのB時点で(H,Y)、どこHであるXのマイナス幅がA

グリッドツリーのリーフブランチはf(C)、最終的にC、相対位置がグリッド内にある場合は文字を出力するか、何もしません。これは、グリッドのコンテンツを出力ストリームに、上から下、左から右に印刷する方法です。実際の配列は作成されません。

テスト

t("ja-r|g-o|ni-|ze|d-|").
t("un|co|p-yr|i|gh-t-ab|-|le-||-").
t("co|mp|l|-ex|i|f|-y|").
t("a").

tt :- t(X),nl,g(X).
tt.

実行中のテスト:

[eclipse] tt.

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe

cccoy
mmply
exify

a

Yes (0.00s cpu)

+1 No actual arrays are produced.の方法です。文法がとてもシンプルで、ショートカットがあるので、この場合はやり過ぎです。
edc65

@ edc65はい、やり過ぎです。しかし、それはcodegolfなので、サイズを最小化しようとしましたが、配列の操作は冗長すぎるでしょう。
コアダンプ

3

Python 2.7、259

z=zip
def p(a,b):
 s,l=sorted([a,b],key=len)
 s+=([s[-1]]*(len(l)-len(s)))
 return z(*(z(*a)+z(*b)))
g=lambda s,t=[]:s and(s[0]=='-'and g(s[1:],t[:-2]+[z(*p(z(*t[-2]),z(*t[-1])))])or(s[0]=='|'and g(s[1:],t[:-2]+[p(t[-2],t[-1])])or g(s[1:],t+[[s[0]]])))or t[0]

gは、指定を取り、文字の2D配列を与える関数です。よりユーザーフレンドリーなバージョンが必要な場合は、次の行を追加して、stdinから仕様を取得し、グリッドを印刷します。

print'\n'.join(''.join(s)for s in g(raw_input()))

テストケース

Input:
a
Output:
a
==========
Input:
co|mp|l|-ex|i|f|-y|
Output:
coooy
mplly
exify
==========
Input:
ja-r|g-o|ni-|ze|d-|
Output:
jronze
aroidd
ggoidd
==========
Input:
un|co|p-yr|i|gh-t-ab|-|le-||-
Output:
unnnnnnn
coyriggl
ppyrihhe
ppyritte
ppyriabe

説明

戦略は単純です:グリッドGが仕様に対して有効な場合、Sの右端の列を繰り返すことGもに対する有効な仕様を与えS、同じことが下の行を繰り返すことにも当てはまります(これの証明は上の構造誘導によるものSです)。したがって、2つの長方形を連結する場合は、サイズが一致するまで小さい方の最後の列/行を追加するだけです(これが関数pの機能です)。


3

Haskell、388 367 352バイト

data C=L{c::Char}|N{t::Int,w::Int,h::Int,l::C,r::C}
q=replicate
[]#[x]=x
(c:i)#(b:a:s)|c=='-'=i#(N 1(max(w a)$w b)(h a+h b)a b:s)|c=='|'=i#(N 2(w a+w b)(max(h a)$h b)a b:s)
(c:i)#s=i#(N 0 1 1(L c)(L c):s)
p i|t i==0=q(h i)$q(w i)$c$l i|t i==2=zipWith(++)(p(l i){h=h i})$p(r i){h=h i,w=w i-w(l i)}|1<2=p(l i){w=w i}++p(r i){w=w i,h=h i-h(l i)}
f=p.(#[])

使用法:f "par-s||e-"->["pas","prs","eee"]

プリティ印刷でのテスト実行:

> putStr $ unlines $ f "par-s||e-"
pas
prs
eee

> putStr $ unlines $ f "co|m|p|il|e|r|-"
comp
iler

> putStr $ unlines $ f "a"
a

> putStr $ unlines $ f "co|mp|l|-ex|i|f|-y|"
coooy
mplly
exify

> putStr $ unlines $ f "ja-r|g-o|ni-|ze|d-|"
jronze
aroidd
ggoidd

> putStr $ unlines $ f "un|co|p-yr|i|gh-t-ab|-|le-||-"
unnnnnnn
coyriggl
ppyrihhe
ppyritte
ppyriabe

仕組み:この関数#は、入力文字列を解析して、印刷する文字を保持CするリーフLまたはノードのいずれかであるツリー構造にしますN。a)N並列結合(t==2)、b)上下結合(t==1)、またはc)一文字の正方形(t==0)のいずれかです。すべてのノードには、幅と高さのフィールドと、左右の子があります。解析後、p子ノードのサイズ(幅x高さ)を再帰的に調整して結合することにより、残りのルートノードを出力します。

編集:プリティプリントの代わりに行のリストとして出力


1

JavaScript(ES6)、283 295

編集今、この(重いゴルフの)JSソリューションは、参照(かなりゴルフに適した)Pythonソリューションより少なくとも短くなります。

cardboard_boxと同様に、一番左の列または一番上の行を繰り返します。

F=w=>(
s=[t=1,l='length'],
[for(c of w)(
  b=s[t],a=s[--t],
  c>'z'?
    s[t]=(G=(a,b,m=b[l]-a[l])=>m?m>0?G([a[0],...a],b):G(a,[b[0],...b]):a.map((r,i)=>r+b[i]))(a,b)
  :c<'a'?
    s[t]=a.map(r=>r[m=b[0][l]-r[l],0].repeat(m>0&&m)+r).concat(b.map(r=>r[0].repeat(m<0&&-m)+r))
  :s[t+=2]=[c]
)],
s[t].join('\n'))

非ゴルフこれは私の最初の、未解決のソリューションです。

F=sp=>{
  s=[]
  for(c of sp){
    a=s.pop(b=s.pop())
    if (c > 'z')
    {
      l = a.length
      m = b.length
      for(; l-m ;)
        l < m ? l = a.unshift(a[0]) : m = b.unshift(b[0])
      s.push(a.map((r,i) => r + b[i]))
    }
    else if (c < 'a')
    {
      l = a[0].length
      m = b[0].length
      s.push(
        a.map(r => r[0].repeat(l < m ? m-l : 0) + r)
        .concat(b.map( r => r[0].repeat( l > m ? l-m : 0) + r))
      )
    }
    else 
    {
      s.push(a,b,[c])
    }
  }
  return s.pop().join('\n')
}

テストFirefox / FireBugコンソールで

;['par-s||e-','co|m|p|il|e|r|-','co|mp|l|-ex|i|f|-y|',
 'ja-r|g-o|ni-|ze|d-|','un|co|p-yr|i|gh-t-ab|-|le-||-']
.forEach(w=>console.log(F(w)))

出力

pas
prs
eee

comp
iler

cccoy
mmply
exify

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe

0

Python 3、251バイト

ここで、私が約束した参考回答を示します。もう少し詳しく説明します。

T=lambda m:list(map(list,zip(*m)))
E=lambda a,b:a[:1]*(len(b)-len(a))+a
H=lambda a,b:[d+c for c,d in zip(E(a,b),E(b,a))]
s=[]
for k in input():s=k>"z"and[H(*s[:2])]+s[2:]or k<"a"and[T(H(*map(T,s[:2])))]+s[2:]or[[[k]]]+s
for r in s[0]:print("".join(r))

これは、STDINから文字列を取得し、STDOUTに出力する完全なプログラムです。アプローチはcardboard_boxのアプローチと同じです。1x1配列の文字をプッシュし、連結に必要な場合は行を複製します。

$ echo "par-s||e-" | python3 gr.py
pas
prs
eee

詳細な説明

  • Tリストの特定のリストを転置します。作業の大部分はzip(*m)行を列にスワップすることによって行われ、残りは結果をリストのリストに変換するだけzipです。タプルのジェネレーターを返すからです。
  • E(a,b)a、の長さに一致するのに十分な回数だけ繰り返された最初の要素で戻りますb。リストに負の数を掛けると空のリストが得られるため、bがより短い場合はをa返しますa
  • H(a,b)リターン水平の連結ab、によって延長される短い方E必要に応じ。
  • s スタックです。
  • forループ、我々反復入力文字列の上に、そして代わるs新しい値によって:それはだ場合|(より大きいz)、我々は2つの値をポップし、彼らのを押すH、それはだ場合-(より低いa)、我々は2つの値をポップ、転置、への供給H、再度転置​​して結果をプッシュし、そうでなければ文字で1x1配列をプッシュします。
  • 最後に、の最初の要素を出力しsます。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.