아스키 아 아트 비교 차 경로 생성


18

2 개 정수 필드의 크기를 나타내는 입력을 감안 x하고 y, 출력 필드 통해 경로.

의 출력 예 5, 4:

#    
#    
# ###
### #

전체 필드는 5 x 4이며 필드를 가로 지르는 해시 마크로 이루어진 경로가 있습니다.

경로는 항상 왼쪽 상단에서 시작하여 오른쪽 하단으로 이동해야합니다. 프로그램이 실행될 때마다 전체 경로가 무작위로 지정되어야합니다. 유효한 모든 경로는 가능한 출력이어야합니다.

경로 규칙은 다음과 같습니다.

  • 해시 마크로 제작

  • 모든 해시는 2 개의 다른 해시에만 연결됩니다 (예 : 경로가 서로 교차하거나 그와 함께 실행되지 않음)

해시가 아닌 공백은 다른 문자로 채워질 수 있지만 일관성이 있어야합니다 (예 : 모든 공백, 모든 기간 등).

예 :

2, 2

##
 #

3, 4

##
 ##
  #
  #

5, 5

#####
    #
    #
    #
    #

6, 5

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

7, 9

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

이런 종류의 경로는 자기를 피하는 무작위 걷기와 비슷하지만 진정한 SAW와 달리 자체 인접 할 수는 없습니다.

경로 연속성과 경로 터치는 대각선없이 정의됩니다.


RBX.Lua 출력 형식이 유효합니까? ;)
devRicher

모든 유효한 경로에 양의 확률이 선택되는 한 확률 분포는 임의적 인 것이 맞습니까?
flawr

@devRicher 예
Rɪᴋᴇʀ

@flawr 예, 맞습니다
Rɪᴋᴇʀ

답변:


11

MATLAB, 316305300 293 바이트

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,'']

다양한 제안과 많은 바이트에 대해 @LuisMendo에게 감사드립니다 =)

온라인으로 사용해보십시오! (보증없이 : Octave에서 실행하려면 약간의 조정이 필요했습니다. 우선 function키워드 를 제거 하고 값을 하드 코딩해야했습니다. 둘째, 공백이 Matlab에서와 같이 올바르게 인쇄되지 않습니다. 또한 다르게 작동 할 수있는 Octave의 컨볼 루션 명령을 확인하십시오.)

입력 출력 예 (7,10)(이미 시간이 오래 걸릴 수 있음) :

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

설명

이렇게하면 원하는 4 개의 연결성을 사용하여 왼쪽 위에서 오른쪽 아래로 순차적으로 경로를 생성 한 다음 거부 샘플링을 사용하여 인접 부품을 가질 수없는 기준을 위반하는 경로를 거부합니다.

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,''];

아 그리고 항상 :

컨볼 루션은 성공의 열쇠입니다.


19

펀칭, 344 바이트

&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-+!#^_

온라인으로 사용해보십시오!

MATLAB 답변에 @flawr이 언급했듯이 필드 크기가 사소한 크기이면 시간이 걸릴 수 있습니다. 실제로 당신은 시간이 끝날 때까지 기다릴 가능성이 높기 때문에 그것이 끝날 때까지 기다릴 가치가없는 상황에 들어가는 것은 매우 쉽습니다.

왜 이런 일이 발생하는지 이해하려면 Befunge의 많은 "시각적 디버거"중 하나에서 실행되는 프로그램을 보는 것이 도움이됩니다. Befunge에서는 데이터와 코드가 동일하므로 시간이 지남에 따라 변경되는 경로를 볼 수 있습니다. 예를 들어, 다음은 느린 경로에서 런의 일부가 어떻게 보이는지 보여주는 짧은 애니메이션입니다.

경로 구조가 구석에 갇히는 것을 보여주는 애니메이션

알고리즘이 필드 경계의 맨 아래에서 왼쪽으로 운명적인 회전을하기로 결정하면, 본질적으로 무의미한 방황의 평생으로 스스로를 비난했습니다. 그 시점부터 울타리가있는 지역의 가능한 모든 단일 경로를 따라 가서 오른쪽으로 돌아가십시오. 그리고이 경우 잠재적 인 경로의 수는 쉽게 천문학이 될 수 있습니다.

결론 : 시간이 오래 걸리는 것 같으면 실행을 중단하고 다시 시작하는 것이 좋습니다.

설명

이것은 기본적으로 재귀 알고리즘으로, 필드를 통해 가능한 모든 경로를 시도한 다음 붙어있을 때마다 이미 수행 된 단계를 해제합니다. Befunge에는 함수 개념이 없기 때문에 재귀 함수는 문제가되지 않지만 스택에서 상태를 추적하여 프로세스를 에뮬레이트 할 수 있습니다.

이것은 우리가 따라야 할 잠재적 인 좌표로 스택을 채우는 방식으로 작동합니다. 그런 다음 스택에서 하나의 세트를 가져 와서 그것이 적합한 지 (즉, 기존 경로와 겹치지 않는 범위 내에 있는지) 확인합니다. 좋은 #위치에 도달하면 해당 위치의 운동장에 기록하고 나중에 역 추적해야 할 경우에 대비하여 세부 사항을 스택에 추가합니다.

그런 다음이 새로운 위치에서 취할 수있는 잠재적 경로를 나타내는 추가 4 개의 좌표 세트를 스택 (임의 순서로)으로 밀고 루프 시작으로 돌아갑니다. 가능한 경로 중 어느 것도 가능하지 않은 경우 #우리는 우리가 작성한 위치를 저장 한 스택의 지점으로 이동 하므로 해당 단계를 취소하고 한 단계 이전부터 잠재적 좌표를 계속 시도합니다.

다음은 다양한 구성 요소가 강조 표시된 코드의 모습입니다.

실행 경로가 강조 표시된 소스 코드

*필드의 너비와 높이를 읽고 0유형 표시 와 함께 시작 좌표를 밀어 역 추적 위치가 아닌 잠재적 경로를 나타냅니다. 공간을 재생 필드에 다시 쓰는 데 필요한 정확한 형식으로 저장되므로 간단한 명령으로 되 돌린
*역 추적 위치 ( 1유형 마커로 표시)를 확인하십시오 p.
*좌표가 여전히 운동장 안에 있는지 확인하십시오. 그들이 범위를 벗어나면, 스택에서 그것들을 떨어 뜨린 후 다음 잠재적 좌표를 시도하기 위해 루프백하십시오.
*값이 범위 내에 있으면 스택에서 다음 두 값을 가져 오십시오.이 값은 이전 단계의 위치입니다 (이 후의 테스트에서 필요함).
*좌표가 경로의 기존 세그먼트와 접촉하는지 확인하십시오. 이전 단계의 위치는이 검사에서 무시됩니다.
*모든 테스트에 성공 #하면 운동장에 a 를 작성 하고 목적지 위치에 도달했는지 확인하십시오.
*만약 있다면, 마지막 경로를 작성 *하고 종료하십시오.
*그렇지 않으면 1나중에 역 추적하기 위해 유형 마커를 사용하여 좌표를 스택에 저장하십시오 .
*이것은 곧 필요한 난수 계산으로 중단됩니다.
*현재 위치에서 도달 할 수있는 4 개의 잠재적 목적지를 푸시하십시오. 임의의 숫자는 푸시되는 순서와 따라야 할 순서를 결정합니다.
* 메인 루프의 시작 부분으로 돌아가 랩에서 다음 값을 처리하십시오.


2
이런 젠장. 설명?
Rɪᴋᴇʀ

@EasterlyIrk 현상금에 감사드립니다. 대단히 감사합니다.
James Holderness

다행 이네요!
Rɪᴋᴇʀ

2

Q 기본, 259 바이트

나는 확실히 사랑한다 GOTO.

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
?"#"

기본 전략 : 각 단계에서 a #를 현재 위치로 인쇄 하고 임의의 방향으로 이동하십시오. a0과 1 의 배열 은 우리가 있었던 곳을 추적합니다. 이동이 합법적이고 끝점으로 GOTO 9이동하는 경우 루프를 종료하고 final을 인쇄하십시오 #. 그렇지 않으면 합법적 인 조치를 취한 경우 다른 조치를 취하십시오. 그렇지 않으면 화면을 지우고 다시 시작하십시오 (역 추적 알고리즘을 코딩하는 것보다 훨씬 골퍼입니다!).

QB64의 랩톱에서 테스트 한 결과 일반적으로 9, 95 초 이내에 결과가 생성 됩니다. 10, 103 초에서 45 초 사이에 실행 됩니다. 이론적으로 모든 유효한 경로에는 0이 아닌 확률이 있지만 곡선이 큰 경로의 확률은 거의 없습니다. 그러나 때때로 하나 또는 두 개의 작은 곡선이있는 경로를 보았습니다.

샘플 경로

요청시 구할 수없는 버전 및 / 또는 자세한 설명이 제공됩니다.


2

R, 225 바이트

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="")}

설명:

우리는 가장자리에 임의의 weigth를 가진 정규 (격자) [x * y] 무향 그래프를 생성 한 다음 시작부터 끝까지 가장 짧은 경로를 찾습니다. 그러나 생성 된 경로에는 두 개의 네이버가있는 셀이있을 수 있습니다.

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

따라서 최단 경로 알고리즘을 두 번 적용해야합니다. 두 번째로 0으로 설정된 현재 발견 경로에있는 것을 제외한 모든 가중치를 1로 설정합니다.

결과

#
#
### 
  # 
  #
  ###

언 골프 드 :

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

자바 스크립트 (ES7), 333 331 330 329 324 318 312 바이트

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>

확장 : #s는 너비 우선 탐색을 사용하여 필드를 통해 경로를 찾을 때까지 배열에 무작위로 배치됩니다. 그런 다음 첫 번째, 따라서 가장 짧은 경로가 출력됩니다. 이렇게하면 경로가 자체적으로 교차하지 않습니다. 특히 더 큰 필드의 경우 경로를 찾기 전에 JS 엔진의 스택을 초과 할 수 있습니다. 언 골프 드 :

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');
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.