2Dブール配列を(直線)ポリゴンに変換


8

チャレンジ

2次元のブール配列(同等に、単色のビットマップ)を指定して、「真」(1)である領域の輪郭を表す一連のポリゴンを出力するプログラムを記述します。

入力は、'#'(ハッシュ)、' '(スペース)、および\n(改行)文字のシーケンスとして提供されます。行の長さが異なる場合があります。その場合、欠落している部分はスペースと見なされます。出力は、(改行で区切られた)ポリゴンのリストである必要があります。各ポリゴンは、(コンマで区切られた)座標のリストで表されます。

例と要件

  1. 座標は時計回りの順序でリストする必要があります。入力:

    #
    

    許容できる出力は次のとおりです。

    (0,0), (1,0), (1,1), (0,1)
    
    (1,0), (1,1), (0,1), (0,0)
    
    (1,1), (0,1), (0,0), (1,0)
    
    (0,1), (0,0), (1,0), (1,1)
    
  2. 互いに素な領域は複数のポリゴンを返す必要があります。入力:

    # #
    

    出力例(実際の出力は2行で構成される必要があります):

    (0,0), (1,0), (1,1), (0,1)
    (2,0), (3,0), (3,1), (2,1)
    
  3. ポリゴンの穴は、別のポリゴンとして、反時計回りの順序でリストする必要があります。入力:

    ###
    # #
    ###
    

    出力例:

    (0,0), (3,0), (3,3), (0,3)
    (1,1), (1,2), (2,2), (2,1)
    
  4. 斜めに隣接する頂点を結合するかどうかは自由に選択できます入力:

    #
     #
    

    出力例:

    (0,0), (1,0), (1,1), (0,1)
    (1,1), (2,1), (2,2), (1,2)
    

    または

    (0,0), (1,0), (1,1), (2,1), (2,2), (1,2), (1,1), (0, 1)
    
  5. 座標のリストは、最適である必要はありません。例えば:

    ##
    

    許容できる出力:

    (0,0), (2,0), (2,1), (0,1)
    
    // Redundant coordinates along a straight line are acceptable
    (0,0), (1,0), (2,0), (2,1), (1,1), (0,1)
    
    // Duplicate start- and end-point are acceptable
    (0,0), (2,0), (2,1), (0,1), (0,0)
    

いつものように、最短のプログラムが「勝ち」ます。


1
ポイント5の結果を説明できますか?直感に反していると思います。
Peter Taylor

CD上の正方形のABでは、BCは常に接続され、ADは常に切断されていると言った場合、それは一貫していますが、正方形は実際には正方形ではなく、形が微妙に変化すると(実質的に)言っているようです#をスペースに、またはその逆に変換します。
Peter Taylor

この獣を分類するのに役立つタグをいくつか追加しました。[optimized-output]は、「座標のリストを最適に短くする必要はない」という条件を表すことを目的としています。誰かがより良い表現を見つけられれば幸いです。
dmckee ---元モデレーターの子猫

少し条件を緩和しましたので、斜めに隣接するものが合流するかどうかは任意になりました。古い要件を守るコメントも削除しました。
Timwi、2015

回答:


3

Perl、345 311 265文字

s!.!$i{$x++}=$&eq'#'!ge,$x=$r+=64for<>;sub a{$d+=@_||3;$d%=4;$y=$x%64;$z=$x>>6;$c.=", ($y,$z)";}for$x(keys%i){if($c=!$v{$x}&$i{$x}&!$i{$x-1}){$i{($x+=(1,64)[$d^3])-(64,65,1)[$d]}?$i{$x-(65,1,0,64)[$d]}?a 1:($x-=(64,1)[$d]):a while$d||!$v{$x}++;print substr$c.$/,3}}

制限事項

入力は64文字以下であると仮定します(ただし、その高さは原則として無制限です)。これは、関連する定数を変更してコードをわずかに長くするだけで、512、8192、またはその他の2の累乗に拡張できます。

やや読みやすいバージョン

最初の行は彼のレーザーでのアイデアの再利用なので、ある程度の信用は暴徒に行きます。残りは完全に私の仕事です。

# Read “%i”nput (this line is essentially mob’s idea, see above)
s!.! $i{$x++} = $& eq '#' !ge, $x = $r += 64 for <>;

# Subroutine to add a vertex to the current polygon and change the current “$d”irection
sub a
{
    $d += @_ || 3;
    $d %= 4;
    $y = $x % 64;
    $z = $x >> 6;
    $c .= ", ($y,$z)";
}

for $x (keys %i)
{
    # Go to the next “upward-pointing” edge that we haven’t already “%v”isited.
    if ($c = !$v{$x} & $i{$x} & !$i{$x-1})
    {
        # We’re going in the “$d”irection of 0=up, 1=left, 2=down, 3=right
        $i{($x += (1,64)[$d^3]) - (64,65,1)[$d]}
        ?  $i{$x - (65,1,0,64)[$d]}
           ?  a 1               # take a 90° turn to the left
           : ($x -= (64,1)[$d]) # move straight ahead
        : a                     # take a 90° turn to the right

        # Only stop if the current “$d”irection is “up” and we encounter a “%v”isited edge
        # (which necessarily is the one we started from)
        while $d || !$v{$x}++;

        # Remove “1, ” and output this polygon
        print substr $c.$/, 3
    }
}

編集

  • (345→312)$x次のイテレーションですでに実行されているため、ターンを取るときに更新する必要がないことに気づきました
  • (312→311)の変更は、1ダウン=、2=左1=左、2=ダウン及び更新$dXORを介して、代わりに、直接
  • (311→265)最も内側の式の繰り返しを削除し、配列を使用してそれをパラメーター化します

2

Python、607文字

コードは、#個の記号を入力順に処理する限り、発見された境界のリストを保持することで機能します。境界は、エッジ(x_start、y_start、x_end、y_endの4タプル)をポリゴンの境界を形成するエッジのリストにマップするテーブルEに格納されます。新しい各#を処理するとき、それは上のポリゴン(p)または左のポリゴン(q)に接続されます。コードは、Eを使用してpとqを見つけ、存在する場合は、現在の#(r)の境界をpとqにマージします。p == qの場合は、ホールが生成されます。

import sys
x=y=N=0
E={}
def P(L):
 if L:print ', '.join(map(lambda z:str(z[:2]),L))
while 1:
 r,a,b,c=[(x,y,x+1,y),(x+1,y,x+1,y+1),(x+1,y+1,x,y+1),(x,y+1,x,y)],(x+1,y,x,y),(x,y,x,y\
+1),sys.stdin.read(1)
 if not c:break
 p,q=E.get(a),E.get(b)
 if'#'==c:
  if p:
   i=p.index(a)
   if q:
    j=q.index(b)
    if p==q:
     if i<j:P(p[i+1:j]);p[i:j+1]=r[1:3]
     else:P(p[i+1:]+p[:j]);p[i:]=r[1:3];p[0:j+1]=[]
    else:p[i:i+1]=r[1:3]+q[j+1:]+q[:j]
   else:p[i:i+1]=r[1:]
  elif q:j=q.index(b);q[j:j+1]=r[:3];p=q
  else:p=r
  for e in p:E[e]=p
 x+=1
 if'\n'==c:y+=1;x=0
for L in E.values():
 if L:P(L);L[:]=[]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.