2D迷路マイナス1D


27

この課題は、2D迷路を1D迷路に変換することです。

概要

+-+-+-+-+-+-+   +-+-+-+-+-+-+                    graph {
| |   |     |   |A|   |    B|   A         B        A -- D
+ + + + +-+-+   + + + + +-+-+    \        |        C -- D
|   | |     |   |   | |     |     \       |        D -- E
+-+-+ +-+-+ +   +-+-+ +-+-+ +      \      |        E -- F
|           |   |C   D E   F|   C---D-E---F        E -- G
+-+-+-+ +-+ +   +-+-+-+ +-+ +         |   |        B -- F
|         | |   |      G  | |     .---G   |        F -- J
+ +-+-+-+ + +   + +-+-+-+ + +   .'   /    |        G -- H
| |       | |   |H|I      |J|   H I-'     J        G -- I
+-+-+-+-+-+-+   +-+-+-+-+-+-+     (ascii)        } // (graphviz dot)       
   Figure 1       Figure 2                 Figure 3

この課題のために、従来の2D迷路は、以下のすべてが当てはまる格子点から形成される長方形の迷路です。

  • 閉じられています(外側のリムは壁で接続されています)。
  • すべての格子点は壁に接続されています
  • 接続されている(2つのスペースXおよびYごとに、それらの間にパスがあります)
  • これは非周期的です(バックトラッキングなしでスペースXからXに戻るパスはありません)

図1は、従来の2D迷路を示しています。これらの迷路には、次の3つの分野があります。

  • 行き止まり -利用可能なパスが1つしかない場所
  • 廊下 -利用可能な2つのパスがある場所
  • 決定ポイント -使用可能なパスが3つまたは4つある場所

そのような迷路ごとに、行き止まりと決定点がノードであり、通路に沿ったパスで接続された2つのノードすべての間にエッジがあるグラフを作成できます。図2は、そのようなノードにラベルを付けた同じ迷路を示しています。図3は、迷路のグラフ(ASCIIおよびGraphvizドット表記)です。

1D迷路

1D迷路にはワープポイントが組み込まれており、それらはペアになっており、文字(どちらの場合も)を使用して識別されます。図4は、1D迷路の例を示しています。それ以外は、図5に示すように、高さが1の2D迷路と同じです。特に図5 +では、でマークされた格子点の位置に注意してください。1D迷路では、左端の壁から始まる他のすべてのキャラクターも格子点です。

                                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  D|  D E|G E F|  F  |  G  |    |  D|  D E|G E F|  F  |  G  |
                                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            Figure 4                         Figure 5

この迷路をナビゲートするためのルールは次のとおりです。すべての動きは、前方(>)または後方(<)のいずれかで表すことができます。ここでのデフォルトの前方および後方は、直感的な空間認識と同じ意味を持ちます。forwardは、すぐ右の位置に移動し、すぐに左の位置に移動します。

ワープポイントは、隣接性と非対称性を非対称的に交換する場所を表します。隣人からワープポイントに来ている場合、2つのワープポイントの位置が入れ替わります。あなたがワープポイントから隣人に来ている場合、それらは交換されません。たとえば、図6では、1から後方に移動すると2に移動します(1がGの隣であり、隣から移動しているため、ポイント2と@が入れ替わります)。2(ワープポイントG)から3に進みます(ここでは、ワープポイントから開始しているため、スワップはありません)。同様に、3から後方に移動すると@に移動します。

        54 2367    89^   @1
|  D|  D E|G E F|  F  |  G  |
                     Y     X
          Figure 6

図6は、一連​​の移動を使用したXからYへのナビゲーションの例も示してい<<>><>>>>>ます。これらの移動により、123456789^それぞれのラベルが付いたポイントにその順序で移動します。次のセクションのコードスニペットを使用して、ご自身で自由に探索してください。

2Dから1Dへの変換

1D迷路を考えると、各ノードが行き止まりまたはワープポイントペアであり、コリドーに沿って接続された2つのノード間にエッジが存在するグラフを作成できます。このグラフにより、1Dと2Dの迷路を比較できます。

たとえば、図4の1D迷路は図1の迷路と同じです。理由を確認するために、図7は行き止まりにラベルを追加します。これらのラベルを使用してグラフを作成すると、図7のグラフは再び図3になります。図8は、このグラフの作成の概要を示しています。

|  D|  D E|G E F|  F  |  G  |
 A   C           B   J H   I 
          Figure 7

|  D|  D E|G E F|  F  |  G  |
+ + + + + + + + + + + + + + + <- lattice points
|A  |C    |     |B   J|H   I| <- dead ends
|A D|C D E|G E F|B F J|H G I| <- all nodes (dead ends+warp points); i.e.:
                                 "where each end is either a dead end
                                  or a warp point pair"; note that each
                                  pair of warp points is the same node.
|A-D|C-D-E|G-E-F|B-F-J|H-G-I| <- corridors; note each is a connection, since
  1   2 3   4 5   6 7   8 9      "edges exist between any two nodes
                                  connected along a corridor"
   graph {                 graph {                 
     A -- D  // 1 <---->     A -- D                
     C -- D  // 2 <---->     C -- D                
     D -- E  // 3 <---->     D -- E                
     G -- E  // 4 <---->     E -- G                
     E -- F  // 5 <---->     E -- F                
     B -- F  // 6 <---->     B -- F                
     F -- J  // 7 <---->     F -- J                
     H -- G  // 8 <---->     G -- H                
     G -- I  // 9 <---->     G -- I                
   }                ^      }
    Built from      |      From Figure 3
     1D maze         `-> isomorphic mappings
                Figure 8

(各グラフのラベルとレイアウトは、説明のために人為的に選択されていることに注意してください。一般的に言えば、これはグラフ同型問題です)。

次のスニペットは、1D迷路のメカニズムと、1D迷路、等価グラフ、および2D迷路間の接続を視覚化するために提供されています。

このスニペットで1D迷路をナビゲートすると、最後にタッチした2つのノードが強調表示されます。同じノードは、等価グラフと2D迷路でも同じように強調表示されます。


一般に、従来の2D迷路では、このタイプの同等の1D迷路を作成できます。もう少し複雑な例を図9に示します。

+-+-+-+-+-+-+   +-+-+-+-+-+-+                   graph {
| |   |   | |   |A|   |   |B|   A         B       A -- D
+ + + + + + +   + + + + + + +    \       /        C -- D
|   | | |   |   |   | | |   |     \     /         D -- E
+-+-+ + +-+-+   +-+-+ + +-+-+      \   /          B -- E
|           |   |C   D E    |   C---D-E           E -- F
+-+-+-+ +-+ +   +-+-+-+ +-+ +         |\          E -- I
|         | |   |      F  | |     .---F \         F -- G
+ +-+-+-+ + +   + +-+-+-+ + +   .'   /   \        G -- H
| |       | |   |G|H      |I|   G H-'     I       H -- I
+-+-+-+-+-+-+   +-+-+-+-+-+-+     (ascii)       } // (graphviz dot)
   Figure 9       Figure 10             Figure 11

|  D|  D E  |F E  |  F  |       |  D|  D E  |F E  |  F  |
                                 A   C     I     B G   H
      Figure 12                       Figure 13

この迷路には4つのパスを持つノードがあります(図10のE)。図11にグラフを示します。図12は同等の1D迷路です。図13は、図11と比較するための行き止まりのラベルが付いた同じ迷路を示しています。

チャレンジ

入力として2D迷路を指定して、2D迷路をワープポイントを持つ1D迷路に変換する関数またはプログラムを作成します。ワープポイントは、それぞれ52文字のいずれかを使用できます。

入力の保証(これらのいずれかが入力で満たされない場合、それを処理する必要はありません):

  • 入力迷路は接続されています(つまり、いつでもどこからでも他の場所に行くことができます)。
  • 入力迷路が閉じられます。
  • 入力迷路は長方形です。
  • すべての格子点はを使用します+
  • 同じ列の格子点の間のすべての壁は使用します |
  • 同じ列の格子点の間のすべての壁はを使用します-
  • すべてのスペースはパスの一部です(そしてすべて迷路の中にあります)。
  • パスはすべてスペースです(これは常に従来の非ワープです)
  • パスの幅は正確に1スペースです。
  • 迷路は、格子上のポイントを接続することによって構築されます。
  • 迷路のグラフには、合計52個以下のノード(つまり、行き止まりと決定ポイント)があります。

出力フォーマット:

  1. 出力は、1D迷路を示す1行でなければなりません。
  2. 出力には、先頭/末尾の空白を含めないでください。ただし、末尾の改行は問題ありません。
  3. 最初のキャラクターとその後のすべてのキャラクターは格子点です。
  4. すべての壁は格子点上にある必要があります。それらの間のすべてのワープポイント。
  5. 1D迷路のグラフは、2D迷路のグラフと同等でなければなりません。
  6. 1D迷路はコンパクトでなければなりません。すべての非格子点は、行き止まり(つまり、壁に隣接)またはワープポイントでなければなりません。
  7. 文字だけあなたの出力では、ワープポイントでなければなりません。各ワープポイントは、ライン上で正確に2回発生します。

例:

|  D|  D E|G E F|  F  |  G  | <- (1,2) The single line output
+ + + + + + + + + + + + + + + <- lattice point spacing... (3) 
                                 (4,6) lattice points are all walls or spaces
                                 (5) See Figure 8
                                 (7) D, E, F, G appear twice; no other labels

これはコードゴルフです。勝者は、最小バイト数の正しい非抜け穴提出です。

テスト中

自明でない迷路には多数の正しい出力があるため、このチャレンジのテストケースはありません。

ただし、C ++でチェッカーを作成しました(このチェッカーは、両方のソリューションをグラフの正規化によってグラフ化します)。

さらに、適切なフォーマットを説明するための例をいくつか示します。

例1

+-+-+-+-+-+-+
| |   |     |
+ + + + +-+-+
|   | |     |
+-+-+ +-+-+ +
|           |
+-+-+-+ +-+ +
|         | |
+ +-+-+-+ + +
| |       | |
+-+-+-+-+-+-+
->
|  D|  D E|G E F|  F  |  G  |

例2

+-+-+-+-+-+-+
| |   |   | |
+ + + + + + +
|   | | |   |
+-+-+ + +-+-+
|           |
+-+-+-+ +-+ +
|         | |
+ +-+-+-+ + +
| |       | |
+-+-+-+-+-+-+
->
|  D|  D E  |F E  |  F  |

その他の例については、こちらをご覧ください


1
1D迷路の説明はまったく明確ではないと思います...より小さい/単純な例を追加すると役立つかもしれません。
mbomb007

それはいいね。助かります。
mbomb007

インタラクティブスクリプトは役に立ちましたが、それでも難しい問題です。だから私はそれをスキップします。これについての私の理解は、せいぜいわずかです。
mbomb007

1D迷路の説明は大雑把です。1D迷路の縦棒文字は、通り過ぎることのできない壁であることを理解するために、図7を読む必要がありました。
edc65

1
:文字の各対はラダーである2D迷路に積み重ね1D迷路は、実施例1 gist.github.com/sparr/36d6355cc4c785a27b12157666169082
SPARR

回答:


3

Pythonの2 IGRAPH492の 369バイト

import igraph,string
def f(s):
 C=s.find('\n')/2;N=' ';g=igraph.Graph(0,[(i,i+j)for i in range(len(s)/(4*C+4)*C)for j in(1,C)if s[(i/C*2+1)*(2*C+2)+i%C*2+2*j+j/C*3]==N]);V=g.vs;g.d=g.degree;O='';V(_d=1)[N]=N;V(_d_gt=2)[N]=list(string.ascii_letters)
 while g.es:
    v=V(_d=1)[0];O+='|'+v[N]
    while g.d(v):w=v.neighbors()[0];g-=(v,w);v=w;O+=N+v[N]if v[N]else''
 print O+'|'

(5行目と6行目はそれぞれタブで始まり、StackExchangeが示す4つのスペースではありません。)

  • 算術演算を再配置して6バイトを節約
  • zipの代わりにスライスを使用して7バイトを保存しました
  • g+=tuple(v.neighbors())代わりに3バイトを保存しましたg.add_edge(*v.neighbors())
  • g-=g.es[g.incident(v)]代わりに使用して7バイトを保存しましたg.delete_edges(g.incident(v))
  • エイリアシングを11バイト保存 g.d=g.degree
  • 52バイト(!)を節約し、次数2の頂点を隣接するエッジで置き換えることにより、すべてのコリドーを縮小するループを排除しました。代わりに、出力ループはこれらの頂点を無視します。
  • 名前を割り当てるときに、igraphは指定された反復可能オブジェクトが長すぎても気にしないことに注意して13バイトを保存しました
  • R行数の変数を持たないことで4バイトを節約し、計算を唯一の使用ポイントに移動しました
  • 第2レベルのインデントをスペースではなくタブに変更して2バイトを保存
  • 保存された6つのバイトは再配置2*(i%C)i%C*22*(i/C)i/C*2、と(C-1)*jj*C-j
  • 保存された4バイトの命名 N='n'
  • 有効な文字のみが表示されるという仮定の下<'-'で、文字がでなくスペースを使用しているかどうかを判断する1バイトを保存しました==' '
  • 次に、の' '代わりに頂点属性に名前を付け、ソース内の2つのリテラルスペース'n'を再利用できN、の==N代わりに<'-'さらに5バイト節約できることに気付きました

やや未使用のバージョンが続きます。基本的な考え方は、最初にすべての迷路の頂点(ゼロインデックスが付けられたときに奇数の行と列を持つスポット)でグラフを作成することです。次の文字がスペースの場合、ではありません|。次の行の対応する文字がスペースではなくスペースである場合、頂点からその直下のエッジまでエッジがあり-ます。

このグラフを作成した後、リーフを選択し、連続する隣接する頂点に沿って進み、コリドーではない場合は名前を書き、使用済みのエッジを削除します。その後、別の葉を取り、すべてのエッジがなくなるまで続けます。

import string
import igraph
def f(s):
  C = s.find('\n')/2 # number of maze vertices in each row
  R = len(s)/(4*C+4) # number of rows
  def strpos(r, c):
    """Index of the vertex at row r, col c in the newline-delimited string s"""
    return (2*r+1)*(2*C+2) + 2*c + 1
  def vertpos(i):
    """Index of the i-th vertex in s"""
    return strpos(i/C, i%C)
  g = igraph.Graph(edges=[(i, i+(C if j else 1))
                          for i in range(R*C)
                          for j in (0, 1)
                          if s[vertpos(i)+(2*C+2 if j else 1)] == ' '])
  V = g.vs # the graph's vertex sequence
  O = ''
  V(_degree=1)['n'] = ' ' # All leaves are named space
  W = V(_degree_gt=2) # All warp points...
  W['n'] = list(string.ascii_letters[:len(W)]) # ...are named successive letters
  while g.es: # while any edges remain...
    v = V(_degree=1)[0] # find a leaf
    O += '|'+v['n'] # start a new 'block'
    while v.degree():
      w = v.neighbors()[0] # pick a neighbor
      g -= (v, w) # delete that edge
      v = w
      if v['n']: # If it's a dead end or warp point...
        O += ' '+v['n'] # ...write out the new neighbor
  print O+'|'

5つのサンプル迷路の結果を見ることができます。(残念ながら、igraphTry It Onlineでは利用できません。これらの結果はSageMathCloudからエクスポートされました。)


4

Haskell- 481 405 387バイト

import Data.List
s&t=elemIndices s t
l=last
c!(x:y:z)=l$(y:c)!(x:z):do{[x:p,q]<-mapM([id,reverse]<*>)[[x],[y]];x&[l q];[[]!((q++p):c++z)]}
c![x]=x:[]!c
c!z=z
main=interact(\m->let{g=' '&m;
u=(\\[k|k<-g,length(v>>=(k&))==2])<$>[]!v;
v=[[x,y]|x<-g,y<-g,elem(y-x-1)[0,head$'\n'&m]];
}in '|':(u>>=(++"|").init.(>>=(:" ").toEnum.((+)<*>(+65).(*32).(`div`26)).l.(-1:).(&(nub$u>>=init.tail)))))

これにより、迷路内にあるスペースのリストが作成され、文字列のインデックスによって番号が付けられ、それを使用して隣接するスペースのすべてのペアが検索されます。次に、最初の要素と最後の要素の一致に基づいてペアをつなぎ合わせてポイントの長いシーケンスにし、コリドーを削除して、各シーケンスが1D迷路の1つの部屋になるようにします。シーケンスは、少なくとも1つの部屋の内部のポイント(ワープポイント)を対応する文字に置き換え、残りをスペースに置き換えることにより、文字列に変換されます。

2D迷路はSTDINから読み取られ、1D迷路はSTDOUTに印刷されます。

編集:大量のものを再配置し、アルゴリズムを少し変更した62バイト、Laikoniが示唆するように置き換えることchrでさらに14バイト削減toEnum

編集2:ロジックを簡素化することで13バイトを節約し(!)、3はリストパターンマッチシュガーを使用>>=して3、2を連結に使用して2を保存しましたu


パターンガードの前に改行やスペースは必要ないと思いますo(x:p)q|x==last q=[q++p]|1>0=[]。たとえば、動作するはずです。
ライコニ

また、のtoEnum代わりに動作するはずでありchr、その後import Data.Charドロップする可能性があります。
ライコニ

最後に、課題がプログラムまたは機能を要求するときにmain=interact(\m->...)、単にに置き換えることができますf m=...。それはあなたに何かを意味するなら、Pythonの答えを打ち負かすのに十分でなければなりません。
ライコニ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.