ヘキソミノを立方体に折り畳むことができますか?


24

私の子供のお気に入りのおもちゃの1つは、このようなセットです。実際、それは私のお気に入りのおもちゃの1つです。私はこのおもちゃで遊んでおり、PPCGチャレンジのアイデアを与えてくれました。以下がその1つです。

ASCII線画を入力として受け取り、それをキューブに折り畳むかどうかを決定するプログラムまたは関数を作成します。

入力

入力は、次のような正方形から構築された正確に1つのhexominoで構成されます。

+-+
| |
+-+

たとえば、有効な入力heximinoは次のとおりです。

+-+
| |
+-+-+-+-+
| | | | |
+-+-+-+-+
  | |
  +-+

出力

  • ヘキソミノを立方体に折り畳める場合の真の値、または
  • それ以外の場合は偽の値。

ちょっとした作業を節約するために、ウィキペディアには次の素晴らしいグラフィックがあります。

  • 35個すべてのヘキソミノ:

  • 立方体に折りたたまれる11個のヘキソミノ:

ノート

  • 入力ヘキソミノには、上記の画像に示されているものだけでなく、回転または反射がある場合があります
  • 入力ヘキソミノには先頭スペースが含まれる場合がありますが、入力されたヘキソミノは自身に対して正しく整列されます
  • 入力ヘキソミノには、行末にスペースがあり、入力終了時に改行が続く場合があります

1
ここに画像処理タグがある理由を説明できますか?質問も回答も、課題を解決するためにどんな種類の画像処理も行う必要はありません。
オプティマイザー

先頭/末尾のスペースに関する明確化:各行の不要な先頭/末尾のスペースと不要な改行は入力に許可されていますか?1000文字以上の入力を管理できますか?
edc65

@ edc65はい、あなたが記述する不要な空白を期待する必要があります。1000文字の最大入力サイズは妥当と思われます-編集します
Digital Trauma

うーん。印刷されたページで、どれくらいの数の立方体のヘキソミノを圧搾、並置できるのだろうか?
luser droog

回答:


7

PMA /スネイル、130

.!(z\ |o{c..!(z\ }3){w=(..!(z\ )|b..!(z\ )o{..!(z\ }2|c{..!(z\ }1,2w..!(z\ )|w{..!(z\ }1,2c..!(z\ }4o..!(z\ )(..!(z\ )|n..!(z\ )`2

またはより「読みやすい」、

?
.!(z\  | o{c..!(z\ }3  )
{w =( ..!(z\ ) | b ..!(z\ ) o {..!(z\ }2  | c {..!(z\ }1,2w..!(z\ ) | w {..!(z\ }1,2c..!(z\  }4
o  ..!(z\ ) ( ..!(z\ ) | n ..!(z\ ) `2

異常なことに、これまでに実装された機能の限られた量で処理できる問題が発生しました。!(z\ )パターンは、現在の位置は、いくつかの「octilinear」方向のスペースがあることを、負のアサーションを使用して、正方形の中央の空間であると判断します。一般的な考え方は、マッチが始まる正方形を基準にして5つの必要な位置のそれぞれに正方形を配置するパターンをチェックすることです。また、2x2の正方形のブロックにないことを確認する必要があります。プログラムが機能する前に、括弧の解析に関するバグを修正する必要がありました。

hexominoがキューブをマップしない場合、0印刷されます。一致する場合、正の整数が表示されます(一致数)。

このpolyominoジェネレーターを採用して、考えられるすべてのテストケースを作成しました。

n=input()
r=range
T=lambda P:set(p-min(p.real for p in P)-min(p.imag for p in P)*1j for p in P)
A=[]
for i in r(1<<18):
 P=[k%3+k/3*1j for k in r(18)if i>>k&1]
 C=set(P[:1])
 for x in P:[any(p+1j**k in C for k in r(4))and C.add(p)for p in P]
 P=T(P)
 if not(C^P or P in A or len(P)-n):
  #for y in r(4):print''.join(' *'[y+x*1j in P] for x in r(6))
  o = [ [' ']*13 for _ in r(9)]
  for y in r(4):
   for x in r(6):
    if y+x*1j in P: X=2*x;Y=2*y; o[Y][X]=o[Y+2][X]=o[Y][X+2]=o[Y+2][X+2]='+'; o[Y][X+1]=o[Y+2][X+1]='-';o[Y+1][X+2]=o[Y+1][X]='|'
  print '\n'.join(map(''.join,o))
  A+=[T([p*1j**k for p in P])for k in r(4)]

hahahahahahahahより「読みやすい」
オプティマイザー

5

ルビー、173 148 145 143バイト

h=->b,c{[c.count(c.max),c.count(c.min),3].max*2<b.max-b.min}
->s{x=[];y=[];i=j=0
s.bytes{|e|e==43&&x<<i|y<<j;i=e<32?0*j+=1:i+1}
h[x,y]||h[y,x]}

最新の変更:/2右側が左側に<置き換えられまし*2た。1セットの削除を許可します()

説明

コードは2つの部分に分かれています。解析を行うメインの名前のない関数とh、チェックを行う変数に割り当てられた補助の名前のない関数です。

x座標とy座標追加列を介してメイン関数走査バイト単位、i,j全ての+シンボルがすることが見出さx[]y[]。その後、h2回呼び出します。初めてヘキソミノが水平(x[]長さとy[]幅を含む)であると仮定し、2回目は垂直であると仮定します。

この関数hは、配列内の縦方向の座標を取り、b次に配列内の横方向の座標を取りますc式によって長さ(平方)を計算します (b.max.b.min)/2。これが3以下の場合、hexominoは他の方向で評価されるため、をh返しますfalse

ヘキソミノの検査により、長さが4の場合、立方体に折りたたまれるヘキソミノ+は、最初と最後の行に2マス(3 シンボル)しかありません。ほとんどの正方形は中央の行に集中しており、これが立方体の赤道になります。この条件は、立方体に折りたたまれる長さ4のヘキソミノにとって必要かつ十分であることが判明しました。

立方体に折りたたまれる長さ5のヘキソミノは1つだけです。+最初と最後の行に3つの正方形(4つのシンボル)があります。長さ5の他のすべてのヘキソミノは+、最初または最後の行に5つ以上のシンボルがあります。

長さ6のヘキソミノは1つだけ+です。各行に7つのシンボルがあります。

これをすべてまとめると、hexominoの長さが3より大きく+、最初と最後の行のシンボルの数(どちらか大きい方)が長さよりも小さいことを確認するだけで十分です。

テストプログラムでゴルフをしていない

#checking function as explained in text
h=->b,c{[c.count(c.max),c.count(c.min),3].max<(b.max-b.min)/2}

#main function for parsing
f=->s{
  x=[]                 #separate assignments required, 
  y=[]                 #otherwise we get 2 pointers to the same array
  i=j=0                #start coordinates 0,0
  s.bytes{|e|          #scan string bytewise
    e==43&&x<<i|y<<j     #if byte is a + symbol (ascii 43) add the coordinates to arrays x and y
    i=e<32?0*j+=1:i+1    #if byte is before ascii 32 assume newline, increment j and zero i. Otherwise increment i
  }
  h[x,y]||h[y,x]       #call h twice, with x and y in each possible order
}



#VALID INPUTS
puts f["
+-+
| |
+-+-+-+-+
| | | | |
+-+-+-+-+
| |
+-+"]

puts f["
+-+
| |
+-+-+-+-+
| | | | |
+-+-+-+-+
  | |
  +-+"]

puts f["
+-+
| |
+-+-+-+-+
| | | | |
+-+-+-+-+
    | |
    +-+"]
puts f["
+-+
| |
+-+-+-+
| | | |
+-+-+-+-+
    | | |
    +-+-+"]

puts f["
+-+
| |
+-+-+-+-+
| | | | |
+-+-+-+-+
      | |
      +-+"]

puts f["
    +-+
    | |
+-+-+-+-+
| | | | |
+-+-+-+-+
    | |
    +-+"]
puts f["
    +-+
    | |
+-+-+-+
| | | |
+-+-+-+-+
    | | |
    +-+-+"]


puts f["
  +-+
  | |
+-+-+-+-+
| | | | |
+-+-+-+-+
    | |
    +-+"]
puts f["
  +-+
  | |
+-+-+-+
| | | |
+-+-+-+-+
    | | |
    +-+-+"]  
puts f["
+-+-+
| | |
+-+-+-+
  | | |
  +-+-+-+
    | | |
    +-+-+"]

puts f["
  +-+-+-+
  | | | |
  +-+-+-+-+-+
      | | | |
      +-+-+-+
"]


#INVALID INPUTS

puts f["
  +-+-+-+
  | | | |
  +-+-+-+
  | | | |
  +-+-+-+
"]


puts f["
  +-+-+-+-+-+-+
  | | | | | | |
  +-+-+-+-+-+-+

"]


puts f["
  +-+-+
  | | |
  +-+-+
  | |
  +-+
  | |
  +-+
  | |
  +-+
  | |
  +-+
"]

puts f["
  +-+-+-+-+-+
  | | | | | |
  +-+-+-+-+-+
    | |
    +-+
"]

puts f["
      +-+
      | |
  +-+-+-+-+-+
  | | | | | |
  +-+-+-+-+-+
"]

puts f["
  +-+-+-+-+
  | | | | |
  +-+-+-+-+-+
        | | |
        +-+-+"]

puts f["
  +-+-+-+-+
  | | | | |
  +-+-+-+-+
      | | |
      +-+-+
"] 


puts f["
  +-+-+-+-+
  | | | | |
  +-+-+-+-+
  | | | |
  +-+ +-+
"]

puts f["
 +-+   +-+
 | |   | |
 +-+-+-+-+
 | | | | |
 +-+-+-+-+
"]

puts f["
   +-+-+
   | | |
 +-+-+-+-+
 | | | | |
 +-+-+-+-+
"]

puts f["
  +-+
  | |
  +-+
  | |
  +-+-+-+-+
  | | | | |
  +-+-+-+-+
"]

puts f["
  +-+
  | |
  +-+-+-+
  | | | |
  +-+-+-+
  | |
  +-+
  | |
  +-+
"]

puts f["
  +-+
  | |
+-+-+-+
| | | |
+-+-+-+
| |
+-+
| |
+-+"]

puts f["
  +-+-+
  | | |
  +-+-+
  | |
  +-+-+
  | | |
  +-+-+
    | |
    +-+
"]

puts f["
  +-+-+-+
  | | | |
  +-+-+-+-+
    | | | |
    +-+-+-+
"]

puts f["
  +-+-+-+
  | | | |
  +-+-+-+
      | |
      +-+-+
      | | |
      +-+-+
"]


puts f["
  +-+-+-+
  | | | |
  +-+-+-+-+
      | | |
      +-+-+
        | |
        +-+
"]

あなたのテキストにペントニモ→ヘキソニモ?
パエロエベルマン

3

JavaScript(ES6)、443 431

バグ修正、入力解析中の問題、空白列の削除の 編集

F=t=>(a=b=c=d=e=f=g=h=0,M=Math.min,
t=t.split('\n').filter(r=>r.trim()>''),
t=t.map(r=>r.slice(M(...t.map(r=>r.search(/\S/))))),
t.map((r,i)=>i&1&&[...r].map((_,j)=>j&1&&r[j-1]==r[j+1]&t[i-1][j]==t[i+1][j]&r[j-1]=='|'
&&(y=i>>1,x=j>>1,z=y*5,w=x*5,a|=1<<(z+x),e|=1<<(w+y),b|=1<<(4+z-x),f|=1<<(4+w-y),c|=1<<(20-z+x),g|=1<<(20-w+y),d|=1<<(24-z-x),h|=1<<(24-w-y)
))),~[1505,2530,3024,4578,252,6552,2529,4577,2499,4547,7056].indexOf(M(a,b,c,d,e,f,g,h)))

これは非常に長く、入力の解析がタスクの大きな部分を占めるため、さらに長くなります。

私がすることは、与えられた入力が11の折りたたみ可能なヘキソミノの1つであるかどうかを確認することです。

各折りたたみ可能なヘキソミノは、5x5ビットマップにマッピングできます(最大8つの異なる、対称性と回転を使用)。ビットマップを25ビット数として、次のコード(非常に単純な入力形式)を使用して、11の注記されたヘキソミノの最小値を見つけました。

h=[ // Foldable hexominoes
'o\noooo\no', ' o\noooo\n o', // pink
'o\noooo\n   o', ' o\noooo\n  o', 'ooo\n  ooo', 'oo\n oo\n  oo', //blue
'o\noooo\n o', 'o\noooo\n  o', 'oo\n ooo\n o', 'oo\n ooo\n  o', 'o\nooo\n  oo' // gray
]
n=[]
h.forEach(t=>(
  a=[],
  t.split('\n')
    .map((r,y)=>[...r]
      .map((s,x)=>s>' '&&(
         a[0]|=1<<(y*5+x),a[1]|=1<<(x*5+y),  
         a[2]|=1<<(y*5+4-x),a[3]|=1<<(x*5+4-y),  
         a[4]|=1<<(20-y*5+x),a[5]|=1<<(20-x*5+y),  
         a[6]|=1<<(24-y*5-x),a[7]|=1<<(24-x*5-y))
     )
  ),
n.push(Math.min(...a))
))

それは与える [1505,2530,3024,4578,252,6552,2529,4577,2499,4547,7056]

したがって、入力文字列が与えられたら、最小ビットマップを見つけるために同じことをし、この番号が事前計算リストに存在する場合はtrueを返す必要があります。

// Not so golfed 

F=t=>(  
  a=b=c=d=e=f=g=h=0,M=Math.min,
  t=t.split('\n').filter(r=>r.trim()>''), // remove blank lines
  t=t.map(r=>r.slice(M(...t.map(r=>r.search(/\S/))))), // remove blank colums to the left
  t.map((r,i)=>i&1&&[...r] // only odd rows
   .map((_,j)=>j&1&& // only odd columns
      r[j-1]==r[j+1]&t[i-1][j]==t[i+1][j]&r[j-1]=='|' // found a cell
         &&(y=i>>1,x=j>>1,z=y*5,w=x*5, // find bitmaps for 8 rotations/simmetries
            a|=1<<(z+x),e|=1<<(w+y),  
            b|=1<<(4+z-x),f|=1<<(4+w-y),  
            c|=1<<(20-z+x),g|=1<<(20-w+y),  
            d|=1<<(24-z-x),h|=1<<(24-w-y)  
    ))),
   ~[1505,2530,3024,4578,252,6552,2529,4577,2499,4547,7056].indexOf(Math.min(a,b,c,d,e,f,g,h)) // look for min
)

スニペットを実行してFirefoxでテストする


何かが足りなくても許してくれます,\nt=tが、2行目の終わり/ 3行目の始まりから行けませんでしたか?
コナーオブライエン

@CᴏɴᴏʀO'Bʀɪᴇɴは6か月後にレビューし、解析コードを10〜15バイト短くすることができました。そのまま、行2のtと行3のtへの割り当てが必要です。行3では、左側でカットする空白文字の数を見つけるために使用されるためです。
edc65
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.