Mê cung 2D trừ 1D


27

Thử thách này là về việc chuyển đổi mê cung 2D thành mê cung 1D.

Tổng quan

+-+-+-+-+-+-+   +-+-+-+-+-+-+                    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

Với mục đích của thử thách này, một mê cung 2D truyền thống là một mê cung hình chữ nhật được hình thành từ các điểm mạng trong đó tất cả các điểm sau:

  • Nó được đóng lại (vành ngoài được kết nối bởi các bức tường).
  • Tất cả các điểm mạng được kết nối với các bức tường
  • Nó được kết nối (cứ hai không gian X và Y có một đường dẫn giữa chúng)
  • Đó là chu kỳ (không có đường dẫn từ bất kỳ khoảng trắng nào trở lại X mà không quay lại)

Hình 1 cho thấy một mê cung 2D truyền thống. Những mê cung này có ba lĩnh vực quan tâm:

  • Ngõ cụt - những nơi chỉ có một con đường có sẵn
  • Hành lang - nơi có hai lối đi có sẵn
  • Điểm quyết định - nơi có ba hoặc bốn đường dẫn có sẵn

Đối với mỗi mê cung như vậy, người ta có thể tạo một biểu đồ trong đó điểm chết và điểm quyết định là các nút và có một cạnh giữa mỗi hai nút được kết nối bằng một đường dẫn dọc theo hành lang. Hình 2 cho thấy cùng một mê cung với các nút như vậy được dán nhãn và Hình 3 biểu đồ của mê cung (theo ký hiệu dấu chấm ASCII và Graphviz).

Mê cung 1D

Mê cung 1D kết hợp các điểm cong vênh, đi theo cặp và được xác định bằng một chữ cái (trong cả hai trường hợp). Hình 4 cho thấy một mê cung ví dụ 1D. Điều này giống hệt với mê cung 2D có chiều cao bằng 1, như trong Hình 5. Đặc biệt lưu ý trong Hình 5, các vị trí điểm lưới được đánh dấu bởi +, thay thế từ trái sang phải; trong mê cung 1D, mọi nhân vật khác bắt đầu bằng bức tường ngoài cùng bên trái cũng là một điểm lưới.

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

Các quy tắc để điều hướng mê cung này là như sau. Mọi di chuyển có thể được biểu diễn dưới dạng tiến ( >) hoặc lùi ( <). Chuyển tiếp và lùi ở đây theo mặc định có cùng ý nghĩa với nhận thức không gian trực quan của chúng tôi; về phía trước đi đến vị trí ngay bên phải, và ngược lại ngay bên trái.

Điểm Warp đại diện cho các vị trí trao đổi kết nối không đối xứng với hàng xóm. Nếu bạn đến từ một người hàng xóm đến một điểm cong vênh, vị trí của hai điểm cong sẽ bị tráo đổi; nếu bạn đến từ một điểm dọc đến một người hàng xóm, họ sẽ không bị tráo đổi. Ví dụ, trong Hình 6, di chuyển ngược từ 1 đưa bạn đến 2 (vì 1 là hàng xóm của G và chúng tôi đang di chuyển từ hàng xóm, các điểm 2 và @ được hoán đổi). Tiến về phía trước từ 2 (điểm warp G) đưa bạn đến 3 (ở đây, chúng tôi đang bắt đầu từ một điểm warp, vì vậy không có trao đổi). Tương tự như vậy, di chuyển ngược từ 3 đưa bạn đến @.

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

Hình 6 cũng cho thấy một điều hướng ví dụ từ X đến Y, sử dụng chuỗi các bước di chuyển <<>><>>>>>. Những động tác này đưa bạn đến các điểm được dán nhãn 123456789^tương ứng, theo thứ tự đó. Hãy tự mình khám phá nó bằng cách sử dụng đoạn mã trong phần tiếp theo.

Chuyển đổi 2D thành 1D

Với một mê cung 1D, người ta có thể tạo một biểu đồ trong đó mỗi nút là một ngõ cụt hoặc một cặp điểm dọc và các cạnh tồn tại giữa bất kỳ hai nút nào được kết nối dọc theo một hành lang. Biểu đồ này cho phép chúng ta so sánh các mê cung 1D và 2D.

Ví dụ, mê cung 1D trong Hình 4 là mê cung tương tự trong Hình 1. Để xem tại sao, Hình 7 thêm nhãn vào ngõ cụt. Sử dụng các nhãn đó để xây dựng biểu đồ, biểu đồ của Hình 7 chỉ đơn giản là Hình 3 một lần nữa. Hình 8 cho thấy một đột phá của việc xây dựng biểu đồ này.

|  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

(Lưu ý rằng các nhãn và bố cục của mỗi biểu đồ được chọn một cách giả tạo để căn chỉnh cho mục đích minh họa; nói chung đây là một vấn đề đẳng cấu đồ thị ).

Đoạn mã sau được cung cấp để giúp trực quan hóa cơ chế của mê cung 1D và kết nối giữa mê cung 1D, biểu đồ tương đương và mê cung 2D.

Khi bạn điều hướng mê cung 1D trong đoạn trích này, hai nút cuối cùng bạn chạm vào sẽ được tô sáng. Các nút giống nhau được tô sáng theo cùng một cách trên biểu đồ tương đương và mê cung 2D.


Nói chung, đối với bất kỳ mê cung 2D truyền thống nào cũng có thể tạo ra mê cung 1D tương đương thuộc loại này. Một ví dụ phức tạp hơn một chút là Hình 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

Mê cung này có một nút có bốn đường dẫn (E trong Hình 10). Hình 11 cho thấy biểu đồ của nó. Hình 12 là một mê cung 1D tương đương; và Hình 13 cho thấy cùng một mê cung với các nhãn cho ngõ cụt để so sánh với Hình 11.

Thử thách

Đưa ra một Mê cung 2D làm đầu vào, hãy viết một hàm hoặc chương trình biến đổi mê cung 2D thành mê cung 1D với các điểm cong vênh. Điểm Warp có thể sử dụng bất kỳ trong số 52 chữ cái trong mỗi trường hợp.

Đảm bảo đầu vào (nếu bất kỳ điều nào trong số này không được đáp ứng trong đầu vào mà bạn không phải đối phó với nó):

  • Mê cung đầu vào được kết nối (nghĩa là bạn luôn có thể đi từ bất kỳ vị trí nào đến bất kỳ vị trí nào khác).
  • Mê cung đầu vào được đóng lại.
  • Mê cung đầu vào là hình chữ nhật.
  • Tất cả các điểm mạng sử dụng +.
  • Tất cả các bức tường giữa các điểm lưới trên cùng một hàng sử dụng |
  • Tất cả các bức tường giữa các điểm lưới trong cùng một cột sử dụng -.
  • Tất cả các không gian là một phần của một con đường (và tất cả bên trong mê cung).
  • Đường dẫn là tất cả các không gian (điều này sẽ luôn là truyền thống, không cong vênh)
  • Đường dẫn chính xác là một không gian rộng.
  • Mê cung được xây dựng bằng cách kết nối các điểm trên một mạng tinh thể.
  • Không có hơn 52 nút tổng (nghĩa là điểm chết cộng với điểm quyết định) trong biểu đồ của mê cung.

Định dạng đầu ra:

  1. Đầu ra của bạn phải là một dòng duy nhất hiển thị mê cung 1D.
  2. Đầu ra của bạn không nên có khoảng trắng hàng đầu / dấu; ngoại trừ một dòng mới là tốt.
  3. Ký tự đầu tiên và mọi ký tự khác sau đó là các điểm mạng.
  4. Tất cả các bức tường nên được trên các điểm lưới; và tất cả các điểm cong vênh giữa chúng.
  5. Biểu đồ của mê cung 1D của bạn phải tương đương với biểu đồ của mê cung 2D.
  6. Mê cung 1D của bạn phải nhỏ gọn; tất cả các điểm không phải mạng tinh thể phải là ngõ cụt (nghĩa là liền kề với các bức tường) hoặc các điểm cong vênh.
  7. Các chữ cái duy nhất trong đầu ra của bạn phải là các điểm cong vênh. Mỗi điểm cong vênh xảy ra trên dòng chính xác hai lần.

Thí dụ:

|  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

Đây là mã golf. Người chiến thắng là bài nộp không kẽ hở chính xác với ít byte nhất.

Kiểm tra

Không có trường hợp thử nghiệm cho thử thách này, vì có một số lượng lớn đầu ra chính xác cho bất kỳ mê cung không tầm thường nào.

Tuy nhiên, tôi đã xây dựng một trình kiểm tra trong C ++ (trình kiểm tra này biểu đồ cả hai giải pháp thông qua việc chuẩn hóa biểu đồ ).

Ngoài ra, đây là một vài ví dụ để giúp minh họa định dạng phù hợp:

ví dụ 1

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

Ví dụ 2

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

Nhiều ví dụ có thể được tìm thấy ở đây .


1
Tôi không nghĩ rằng lời giải thích về mê cung 1D rất rõ ràng ... Có thể thêm một ví dụ nhỏ hơn / đơn giản hơn sẽ giúp ích.
mbomb007

Điều đó thật tuyệt. Vâng, điều đó có ích.
mbomb007

Mặc dù kịch bản tương tác của bạn đã giúp, nhưng nó vẫn là một vấn đề khó khăn. Vì vậy, tôi chỉ cần bỏ qua nó. Sự hiểu biết của tôi về điều này vẫn còn khó khăn nhất.
mbomb007

Mô tả về mê cung 1D còn sơ sài. Tôi đã phải đọc đến hình 7 để hiểu rằng các ký tự thanh dọc trong mê cung 1D là những bức tường mà bạn không thể vượt qua.
edc65

1
ví dụ 1 với mê cung 1d xếp chồng lên nhau thành mê cung 2d trong đó mỗi cặp chữ cái là một bậc thang: gist.github.com/sparr/36d6355cc4c785a27b12157666169082
Sparr

Câu trả lời:


3

Python 2 với igraph , 492 369 byte

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+'|'

(Mỗi dòng thứ năm và thứ sáu, mỗi dòng bắt đầu bằng một tab, không phải bốn khoảng trắng như StackExchange hiển thị.)

  • Đã lưu sáu byte sắp xếp lại một số số học
  • Đã lưu bảy byte bằng cách sử dụng một lát thay vì zip
  • Đã lưu ba byte bằng cách sử dụng g+=tuple(v.neighbors())thay vìg.add_edge(*v.neighbors())
  • Đã lưu bảy byte bằng cách sử dụng g-=g.es[g.incident(v)]thay vìg.delete_edges(g.incident(v))
  • Đã lưu mười một byte bí danh g.d=g.degree
  • Đã lưu 52 byte (!) Loại bỏ một vòng lặp ký hợp đồng với tất cả các hành lang bằng cách thay thế các đỉnh bậc 2 bằng một cạnh giữa các hàng xóm của chúng. Thay vào đó, vòng lặp đầu ra chỉ bỏ qua các đỉnh này.
  • Đã lưu 13 byte nhận thấy rằng khi gán tên, igraph không quan tâm nếu lần lặp được cung cấp quá dài
  • Đã lưu bốn byte bằng cách không có biến Rcho số lượng hàng, di chuyển phép tính của nó sang điểm sử dụng duy nhất
  • Đã lưu hai byte thay đổi thụt cấp độ thứ hai thành các tab thay vì khoảng trắng
  • Lưu Sáu byte sắp xếp lại 2*(i%C)để i%C*2, 2*(i/C)đến i/C*2, và (C-1)*jđểj*C-j
  • Đã lưu bốn byte đặt tên N='n'
  • Đã lưu một byte xác định nếu một ký tự là không gian sử dụng <'-'chứ không phải ==' ', theo giả định rằng chỉ có các ký tự hợp lệ xuất hiện.
  • Sau đó nhận ra tôi có thể đặt tên thuộc tính vertex ' 'thay vì 'n'và sử dụng lại Ncho hai khoảng trắng trong nguồn và ==Nthay vào đó <'-', lưu thêm năm byte

Một phiên bản hơi vô dụng theo sau. Ý tưởng cơ bản là trước tiên tạo một biểu đồ trên tất cả các đỉnh mê cung (các điểm có hàng và cột lẻ khi được lập chỉ mục bằng không.) Có một cạnh từ một đỉnh đến đỉnh tiếp theo trên cùng một hàng nếu ký tự sau là khoảng trắng , và không |. Có một cạnh từ đỉnh đến một bên phải bên dưới nếu ký tự tương ứng trong hàng sau là khoảng trắng, và không -.

Sau khi xây dựng biểu đồ này, chúng tôi chọn bất kỳ chiếc lá nào và đi dọc theo các đỉnh liền kề nhau, viết tên của chúng nếu chúng không phải là hành lang và xóa các cạnh đã sử dụng cho đến khi chúng tôi bị kẹt. Sau đó, chúng tôi lấy một chiếc lá khác và tiếp tục cho đến khi tất cả các cạnh đã biến mất.

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+'|'

Bạn có thể thấy kết quả cho năm mê cung ví dụ . (Thật không may, igraphkhông có sẵn trên Dùng thử trực tuyến; những kết quả này đã được xuất từ SageMathCloud .)


4

Haskell - 481 405 387 byte

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)))))

Điều này tạo ra một danh sách các không gian trong mê cung, được đánh số theo chỉ mục trong chuỗi và sử dụng nó để tìm tất cả các cặp không gian liền kề. Sau đó, nó ghép các cặp lại với nhau thành chuỗi điểm dài hơn dựa trên các yếu tố đầu tiên / cuối cùng và loại bỏ các hành lang, sao cho mỗi chuỗi là một phòng trong mê cung 1D. Các chuỗi sau đó được dịch thành một chuỗi bằng cách thay thế các điểm trên phần bên trong của ít nhất một phòng (các điểm cong vênh) thành các chữ cái tương ứng và phần còn lại vào không gian.

Mê cung 2D được đọc từ STDIN và mê cung 1D được in thành STDOUT.

Chỉnh sửa: Giảm bằng 62 byte sắp xếp lại một loạt các công cụ và sửa đổi thuật toán một chút, và 14 khác bằng cách thay thế chrbằng toEnumnhư được đề xuất bởi Laikoni.

Chỉnh sửa 2: Đã lưu thêm 13 byte bằng cách đơn giản hóa logic trong (!), 3 bằng cách sử dụng mẫu danh sách khớp với đường và 2 bằng cách sử dụng >>=để nối vào u.


Tôi nghĩ rằng bạn không cần các dòng mới và khoảng trắng trước các mẫu bảo vệ, ví dụ như o(x:p)q|x==last q=[q++p]|1>0=[]cũng nên hoạt động.
Laikoni

Cũng toEnumnên làm việc thay vì chr, sau đó import Data.Charcó thể được bỏ.
Laikoni

Và cuối cùng, khi thử thách yêu cầu một chương trình hoặc chức năng, bạn có thể thay thế main=interact(\m->...)bằng chỉ f m=.... Điều này là đủ để đánh bại câu trả lời của con trăn, nếu điều đó có ý nghĩa với bạn.
Laikoni
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.