Tạo một con đường không giao nhau ascii-art


18

Cho 2 đầu vào số nguyên biểu thị kích thước của trường, xy, xuất một đường dẫn qua trường.

Ví dụ đầu ra cho 5, 4:

#    
#    
# ###
### #

Toàn bộ trường là 5 x 4 và có một đường dẫn được tạo bởi các dấu băm ngang qua trường.

Đường dẫn phải luôn bắt đầu ở góc trên cùng bên trái và đi xuống dưới cùng bên phải. Toàn bộ đường dẫn nên được chọn ngẫu nhiên mỗi khi chương trình được chạy. Mỗi đường dẫn hợp lệ phải là một đầu ra có thể.

Các quy tắc cho các đường dẫn là:

  • Làm bằng dấu

  • Mỗi hàm băm chỉ được kết nối với 2 giá trị băm khác (tức là đường dẫn không giao nhau hoặc chạy dọc theo chính nó)

Các không gian không băm có thể được lấp đầy nó với bất kỳ ký tự nào khác, nhưng nó phải nhất quán (tức là tất cả các khoảng trắng, tất cả các dấu chấm, v.v.)

Ví dụ:

2, 2

##
 #

3, 4

##
 ##
  #
  #

5, 5

#####
    #
    #
    #
    #

6, 5

## ###
 # # #
## # #
# ## #
###  #

7, 9

#######
      #
####  #
#  #  #
#  #  #
#  #  #
#  ####
#
#######

Loại đường dẫn này tương tự như đi bộ ngẫu nhiên tự tránh, tuy nhiên nó không thể liền kề với chính nó không giống như một SAW thực sự.

Liên tục đường dẫn và chạm đường dẫn đều được xác định mà không có đường chéo.


Định dạng đầu ra RBX.Lua hợp lệ? ;)
devR Rich

Có đúng không, miễn là mọi đường dẫn hợp lệ có xác suất dương được chọn, phân phối xác suất là tùy ý?
flawr

@devR Rich yeah
Rɪᴋᴇʀ

@flawr yeah, đúng vậy
R

Câu trả lời:


11

MATLAB, 316 305 300 293 byte

function P=f(a,b);z(a,b)=0;P=z;c=@(X)conv2(+X,[0,1,0;1,1,1;0,1,0],'s');B=1;while B;P=z;P(1)=1;for K=1:a*b;S=z;S(a,b)=1;for L=2:a*b;S(~S&c(S)&~P)=L;end;[i,j]=find(S&c(P==K));if i;r=randi(nnz(i));else;break;end;P(i(r),j(r))=K+1;if P(a,b);break;end;end;B=any(any(c(P>0)>3));end;P(P>0)=35;P=[P,'']

Cảm ơn @LuisMendo về các đề xuất khác nhau và một loạt byte =)

Hãy thử trực tuyến! (Không có bảo hành: Lưu ý rằng cần có một vài điều chỉnh để chạy nó trên Octave: Trước hết tôi cần phải xóafunction từ khóa và mã hóa các giá trị, thứ hai: Các khoảng trắng không được in chính xác như trong Matlab. Ngoài ra, tôi không kiểm tra các lệnh chập của Octave, có thể hoạt động khác đi.)

Ví dụ đầu ra cho đầu vào (7,10)(có thể mất khá nhiều thời gian):

#         
#         
##        
 ##       
  #   ### 
  #   # ##
  #####  #

Giải trình

Điều này tạo ra các đường dẫn liên tục từ trên cùng bên trái xuống dưới cùng bên phải với kết nối 4 mong muốn và sau đó sử dụng lấy mẫu từ chối để từ chối các đường dẫn vi phạm tiêu chí mà bạn không thể có các phần phụ.

function P=f(a,b);
z(a,b)=0;                                 % a matrix of zeros of the size of th efield
P=z;                                    
c=@(X)conv2(+X,[0,1,0;1,1,1;0,1,0],'s');  % our convolution function, we always convolute with the same 4-neighbourhood kernel
B=1;
while B;                                  % while we reject, we generate paths:
    P=z;
    P(1)=1;                               % P is our path, we place the first seed
    for K=1:a*b;                          % in this loop we generate the all shortest paths (flood fill) from the bottom right, withot crossing the path to see what fiels are reachable from the bottom left
        S=z;
        S(a,b)=1;                         % seed on the bottom left
        for L=2:a*b;
            S(~S&c(S)&~P)=L;              % update flood front
        end;
        [i,j]=find(S&c(P==K));            % find a neighbour of the current end of the path, that is also reachable from the bottom left
        if i;                             % if we found some choose a random one
            r=randi(nnz(i));
        else;
            break;                        % otherwise restart (might not be necessary, but I'm too tired to think about it properly=)
        end;
        P(i(r),j(r))=K+1;                 % update the end of the current path
        if P(a,b);                        % if we finished, stop continuing this path
            break;
        end;
    end;
    B=any(any(c(P>0)>3));                 % check if we actually have a valid path
end;
P(P>0)=35;                                % format the path nicely
P=[P,''];

Ồ và như mọi khi:

Thuyết phục là chìa khóa thành công.


19

Befunge, 344 byte

&v>>>#p_:63p:43g`\!+v>/*53g+\01g:2%2*1-\2/!*63g+\0\:v
 40$ v++!\`g14:p35:\<^2\-1*2%2p10::%4+g00:\g36\g35-1_v
#11^$_83p73v >1+:41g`!#v_$,1+:43g`!#v_@>->2>+00p+141^_
<p1^     vp< ^,g+7g36:<<<<1+55p36:<<<< ^1?0^#7g36g35*
8&p|!++!%9#2g+7g10\*!-g38g10!-g37:g00!!*<>3^
443>:!#v_>>1-::3%1-:53g+00p\3/1-:63g+01p^
^>^>>$#<"#"53g63g7+p41g53g-43g63g-+!#^_

Hãy thử trực tuyến!

Như @flawr đã đề cập trong câu trả lời MATLAB của họ, điều này có thể mất một thời gian nếu kích thước trường là bất kỳ kích thước không tầm thường. Trên thực tế, thật dễ dàng để rơi vào một tình huống mà thực sự không đáng để cố gắng chờ đợi nó kết thúc, bởi vì bạn hoàn toàn có thể chờ đợi cho đến khi kết thúc thời gian.

Để hiểu lý do tại sao điều này xảy ra, thật hữu ích khi xem chương trình khi nó đang thực thi trong một trong nhiều "trình gỡ lỗi trực quan" của Befunge. Vì dữ liệu và mã là cùng một thứ trong Befunge, bạn sẽ có thể xem đường dẫn khi nó thay đổi theo thời gian. Ví dụ, đây là một hình ảnh động ngắn cho thấy một phần của hoạt động trên một con đường chậm có thể trông như thế nào.

Hoạt hình cho thấy việc xây dựng đường dẫn bị kẹt ở một góc

Một khi thuật toán quyết định thực hiện bước ngoặt định mệnh đó sang bên trái ở dưới cùng của ranh giới trường, về cơ bản, nó đã tự kết án bản thân mình trong suốt cuộc đời lang thang vô mục đích. Từ thời điểm đó, nó phải đi theo từng con đường có thể trong khu vực có rào chắn đó trước khi nó có thể lùi ra và thử rẽ sang phải. Và số lượng các con đường tiềm năng trong những trường hợp này có thể dễ dàng trở thành thiên văn.

Điểm mấu chốt: Nếu có vẻ mất nhiều thời gian, có lẽ bạn nên hủy bỏ việc thực hiện và bắt đầu lại.

Giải trình

Về cơ bản, đây là một thuật toán đệ quy, thử mọi đường dẫn có thể đi qua trường và sau đó tháo gỡ các bước đã được thực hiện bất cứ khi nào nó bị kẹt. Vì Befunge không có khái niệm về các hàm, nên một hàm đệ quy sẽ không còn nữa, nhưng chúng ta có thể mô phỏng quá trình bằng cách theo dõi trạng thái trên ngăn xếp.

Điều này hoạt động bằng cách điền vào ngăn xếp với tọa độ tiềm năng mà chúng ta có thể muốn theo dõi. Sau đó, chúng tôi kéo một bộ từ ngăn xếp và kiểm tra xem nó có phù hợp không (nghĩa là trong phạm vi và không chồng lấp với một đường dẫn hiện có). Khi chúng tôi đã có một vị trí tốt, chúng tôi viết một# sân chơi tại vị trí đó và thêm các chi tiết đó vào ngăn xếp trong trường hợp chúng tôi cần quay lại sau.

Sau đó, chúng tôi đẩy thêm bốn bộ tọa độ vào ngăn xếp (theo thứ tự ngẫu nhiên) cho biết các đường dẫn tiềm năng mà chúng tôi có thể đi từ vị trí mới này và quay lại điểm bắt đầu của vòng lặp. Nếu không có đường dẫn tiềm năng nào khả thi, chúng tôi sẽ đến điểm trên ngăn xếp nơi chúng tôi đã lưu vị trí của# chúng ta đã viết, vì vậy chúng ta sẽ hoàn tác bước đó và tiếp tục thử tọa độ tiềm năng từ một bước trước.

Đây là những gì mã trông giống như với các phần thành phần khác nhau được tô sáng:

Mã nguồn với các đường dẫn thực thi được tô sáng

*Đọc chiều rộng và chiều cao của trường và đẩy tọa độ bắt đầu cùng với 0điểm đánh dấu loại để chỉ ra đường dẫn tiềm năng thay vì vị trí quay lui.
*Kiểm tra các vị trí quay lui (được biểu thị bằng 1loại đánh dấu) được hoàn nguyên bằng một plệnh đơn giản , vì chúng được lưu trữ ở định dạng chính xác cần thiết để ghi lại khoảng trống vào sân chơi.
*Kiểm tra xem tọa độ có còn trong sân chơi không. Nếu chúng nằm ngoài phạm vi, thả chúng khỏi ngăn xếp và lặp lại để thử tọa độ tiềm năng tiếp theo.
*Nếu chúng nằm trong phạm vi, hãy lấy hai giá trị tiếp theo từ ngăn xếp, đó là vị trí của bước trước đó (bắt buộc trong thử nghiệm theo sau điều này).
*Kiểm tra xem tọa độ có tiếp xúc với một đoạn đường dẫn hiện có không. Vị trí của bước trước rõ ràng bị bỏ qua khỏi kiểm tra này.
*Nếu tất cả thử nghiệm thành công, hãy viết một #vào sân chơi và kiểm tra xem chúng tôi đã đến được vị trí đích chưa.
*Nếu chúng ta có, viết ra đường dẫn cuối cùng *và thoát.
*Mặt khác, lưu tọa độ vào ngăn xếp với 1điểm đánh dấu để quay lại sau.
*Điều này bị gián đoạn với một phép tính số ngẫu nhiên mà chúng ta sẽ cần sớm.
*Đẩy bốn điểm đến tiềm năng có thể đạt được từ vị trí hiện tại. Số ngẫu nhiên xác định thứ tự mà chúng được đẩy và do đó thứ tự chúng sẽ được tuân theo.
* Quay trở lại điểm bắt đầu của vòng lặp chính và xử lý các giá trị tiếp theo trên ngăn xếp.


2
Bò thần. Giải trình?
Rɪᴋᴇʀ

@EasterlyIrk Cảm ơn bạn đã nhận tiền thưởng. Nó được nhiều đánh giá cao.
James Holdiness

Vui vì nó hữu ích!
Rɪᴋᴇʀ

2

QBasic, 259 byte

Tôi chắc chắn yêu GOTOs.

RANDOMIZE TIMER
INPUT w,h
DO
CLS
x=1
y=1
REDIM a(w+3,h+3)
2a(x+1,y+1)=1
LOCATE y,x
?"#"
d=INT(RND*4)
m=1AND d
x=x+m*(d-2)
y=y-d*m+m+d-1
c=a(x,y+1)+a(x+2,y+1)+a(x+1,y)+a(x+1,y+2)=1
IF(x=w)*c*(y=h)GOTO 9
IF(x*y-1)*x*y*c*(x<=w)*(y<=h)GOTO 2
LOOP
9LOCATE y,x
?"#"

Chiến lược cơ bản: ở mỗi bước, in a #đến vị trí hiện tại và di chuyển theo hướng ngẫu nhiên. Mảng a0 và 1 theo dõi chúng ta đã ở đâu. Nếu di chuyển là hợp pháp và đưa chúng ta đến điểm cuối, GOTO 9để thoát khỏi vòng lặp và in bản cuối cùng #. Khác, nếu di chuyển là hợp pháp, thực hiện một bước khác. Khác, xóa màn hình và bắt đầu lại (nhiều hơn so với mã hóa thuật toán quay lui!).

Đã thử nghiệm trên máy tính xách tay của tôi trong QB64, điều này thường tạo ra kết quả 9, 9trong năm giây hoặc ít hơn. Chạy 10, 10đã mất bất cứ nơi nào từ ba đến 45 giây. Về mặt lý thuyết, tất cả các đường dẫn hợp pháp đều có xác suất khác không, nhưng xác suất của một đường dẫn có đường cong lớn là rất nhỏ. Tôi thỉnh thoảng nhìn thấy các đường dẫn với một hoặc hai đường cong nhỏ, mặc dù:

Đường dẫn mẫu

Phiên bản Ungolfed và / hoặc giải thích sâu có sẵn theo yêu cầu.


2

R, 225 byte

function(x,y){library(igraph);a=matrix(rep(" ",x*y),c(y,x));g=make_lattice(c(y,x));w=runif(ecount(g));for (i in 1:2){v=shortest_paths(g,1,x*y,weights=w)$vpath[[1]];w[]=1;w[E(g)[v%--%v]]=0;};a[v]="#";cat(rbind(a,"\n"),sep="")}

Giải trình:

Chúng ta tạo một biểu đồ vô hướng (mạng tinh thể) [x * y] thông thường với các điểm ngẫu nhiên trên các cạnh sau đó chúng ta tìm thấy con đường ngắn nhất từ ​​đầu đến cuối. Tuy nhiên, trong đường dẫn được tạo có thể có các ô có nhiều hơn hai neig Harbor chẳng hạn:

#
#
####
  ##
  #
  ###

Vì vậy, chúng ta nên áp dụng thuật toán đường dẫn ngắn nhất hai lần. Trong lần thứ hai, chúng tôi đặt tất cả các trọng số thành 1 ngoại trừ các trọng số trong đường dẫn tìm thấy hiện tại được đặt thành 0;

kết quả

#
#
### 
  # 
  #
  ###

Ung dung:

function(x,y){
    library(igraph);#igraph library should be installed
    a=matrix(rep(" ",x*y),c(y,x));#ASCII representation of the graph
    g=make_lattice(c(y,x));# regular graph
    w=runif(ecount(g));#weights
    for (i in 1:2){
        #find vertices that are in the path
        v=shortest_paths(g,1,x*y,weights=w)$vpath[[1]];
        #set all weights to 1 except those that are in the current found path that set to 0
        w[]=1;
        w[E(g)[v%--%v]]=0;
    }
    a[v]="#";
    cat(rbind(a,"\n"),sep="")
}

1

JavaScript (ES7), 333 331 330 329 324 318 312 byte

f=
(h,w,c=[...Array(h)].map(_=>Array(w).fill` `),g=a=>{for(z of b=[[[h-1,w-1]]])a.map(([x,y])=>b.every(([[i,j]])=>i-x|j-y)&(z[0][0]-x)**2+(z[0][1]-y)**2<2&&b.push([[x,y],...z]));return b.find(([[x,y]])=>!x&!y)||g([...a,[h,w].map(n=>Math.random()*n|0)])})=>g([]).map(([x,y])=>c[x][y]=`#`)&&c.map(a=>a.join``).join`
`
Height: <input type=number min=1 id=h>Width: <input type=number min=1 id=w><input type=button value="Generate!" onclick=o.textContent=f(+h.value,+w.value)><pre id=o>

Mở rộng: #s được đặt ngẫu nhiên trong mảng cho đến khi tìm thấy đường dẫn qua trường bằng cách sử dụng tìm kiếm theo chiều rộng; con đường đầu tiên và ngắn nhất là đầu ra; điều này đảm bảo rằng đường dẫn không giao nhau. Lưu ý rằng đặc biệt đối với các trường lớn hơn, có thể vượt quá ngăn xếp của công cụ JS trước khi tìm thấy đường dẫn. Ung dung:

function r(n) {
    return Math.floor(Math.random() * n);
}
function f(h, w) {
    var a = []; // array of placed #s
    var b; // breadth-first search results
    var c;
    do {
        a.push([r(h), r(w)]); // place a # randomly
        b = [[[h - 1, w - 1]]]; // start from bottom right corner
        for (z of b) // breadth-first search
            for ([x, y] of a) // find possible next steps
                if (!b.some(([[i, j]]) => i == x && j == y))
                    if ((z[0][0] - x) ** 2 + (z[0][1] - y) ** 2 < 2)
                        if (x || y)
                            b.push([[x, y], ...z]); // add to search
                        else if (!c)
                            c = [[x, y], ...z]; // found path
    } while (!c);
    a = [...Array(h)].map(() => Array(w).fill(' '));
    for ([x, y] of c) // convert path to output
        a[x][y] = '#';
    return a.map(b => b.join('')).join('\n');
}
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.