Ascii-art kesişmeyen bir yol oluşturun


18

2 tam sayı alanının boyutunu temsil eden girişleri, göz önüne alındığında xve yçıkış alan üzerinden bir yol.

Örnek çıktı 5, 4:

#    
#    
# ###
### #

Tüm alan 5 x 4'tür ve alanı geçen karma işaretlerden oluşan bir yol vardır.

Yol her zaman sol üst köşeden başlamalı ve sağ alt köşeye gitmelidir. Program her çalıştırıldığında tüm yol rasgele seçilmelidir. Her geçerli yol olası bir çıktı olmalıdır.

Yol kuralları:

  • Karma işaretlerden yapılmıştır

  • Her karma yalnızca 2 karma değere bağlıdır (yani, yol kendi kendine kesişmez veya yan yana ilerlemez)

Karma olmayan boşluklar başka herhangi bir karakterle doldurulabilir, ancak tutarlı olmalıdır (yani tüm boşluklar, tüm dönemler vb.)

Örnekler:

2, 2

##
 #

3, 4

##
 ##
  #
  #

5, 5

#####
    #
    #
    #
    #

6, 5

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

7, 9

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

Bu tür bir yol, kendinden kaçınan rastgele bir yürüyüşe benzer, ancak gerçek bir TESTERE aksine kendisine bitişik olamaz.

Yol sürekliliği ve yol dokunuşu diyagonal olmadan tanımlanır.


RBX.Lua çıktı biçimi geçerli mi? ;)
devRicher

Her geçerli yolun seçilme olasılığı pozitif olduğu sürece, olasılık dağılımının keyfi olduğu doğru mudur?
Kusur

@devRicher yeah
Rɪᴋᴇʀ

@flawr evet, bu doğru
Rɪᴋᴇʀ

Yanıtlar:


11

MATLAB, 316305300293 bayt

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 çeşitli öneriler ve bir sürü bayt için teşekkürler =)

Çevrimiçi deneyin! (Garanti olmadan: Octave üzerinde çalışmasını sağlamak için birkaç ayar yapılması gerektiğini unutmayın: Öncelikle functionanahtar kelimeyi kaldırmam ve değerleri sabit kodlamam gerekiyordu , ikincisi: Boşluklar Matlab'daki gibi doğru şekilde yazdırılmıyor. farklı hareket edebilecek Octave'nin evrişim komutlarını kontrol edin.)

Giriş için örnek çıktı (7,10)(zaten biraz zaman alabilir):

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

açıklama

Bu, istenen 4 bağlantıyla sol üstten sağa doğru sıralı yollar oluşturur ve daha sonra, uygun parçalara sahip olamayacağınız kriteri ihlal eden yolları reddetmek için reddetme örneklemesi kullanır.

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

Oh ve her zamanki gibi:

Evrişim başarının anahtarıdır.


19

Befunge, 344 bayt

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

Çevrimiçi deneyin!

MATLAB yanıtlarında @flawr'ın belirttiği gibi, alan boyutu önemsiz olmayan bir boyuttaysa bu biraz zaman alabilir. Aslında, bitmesini beklemeye gerçekten değmeyecek bir duruma girmek oldukça kolaydır, çünkü zamanın sonuna kadar beklemeniz muhtemeldir.

Bunun neden olduğunu anlamak için, programı Befunge'nin birçok "görsel hata ayıklayıcısından" birinde yürütürken görüntülemek yararlıdır. Befunge'de veri ve kod aynı şey olduğundan, yolu zaman içinde değiştikçe görüntüleyebilirsiniz. Örneğin, yavaş bir yolda koşunun bir kısmının nasıl görünebileceğini gösteren kısa bir animasyon.

Kendini bir köşeye sıkışmış yol inşaatını gösteren animasyon

Algoritma, alan sınırının altındaki sola doğru bu kader dönüşünü yapmaya karar verdiğinde, esasen kendisini ömür boyu amaçsız bir gezintiye mahkemm etti. Bu noktadan sonra, çitle çevrili alanda geri dönüp sağa dönmeyi denemeden önce mümkün olan her yolu takip etmelidir. Ve bu durumlarda potansiyel yolların sayısı kolayca astronomik hale gelebilir.

Alt satır: Uzun zaman alıyor gibi görünüyorsa, muhtemelen yürütmeyi iptal etmek ve tekrar başlamak iyi bir fikirdir.

açıklama

Bu temelde, alandaki olası her yolu deneyen ve daha sonra sıkıştığında izlenen çözme adımlarını tekrarlayan bir algoritmadır. Befunge işlev kavramına sahip olmadığından, yinelemeli bir işlev söz konusu değildir, ancak yığındaki durumu izleyerek süreci taklit edebiliriz.

Bu, yığını takip etmek isteyebileceğimiz potansiyel koordinatlarla doldurarak çalışır. Sonra bir kümeyi yığından çekeriz ve uygun olup olmadığını kontrol ederiz (yani aralıkta ve mevcut bir yolla çakışmıyor). İyi bir noktaya #ulaştığımızda, o konumdaki oyun alanına a yazarız ve daha sonra geri gitmemiz gerektiğinde bu ayrıntıları yığına ekleriz.

Daha sonra, bu yeni konumdan alabileceğimiz potansiyel yolları belirten yığına (rastgele sırayla) ek dört koordinat kümesi ekliyoruz ve döngünün başına atlıyoruz. Potansiyel yollardan hiçbiri uygun değilse, #yazdığımız yerin konumunu kaydettiğimiz yığındaki noktaya ulaşacağız , bu nedenle bu adımı geri alacağız ve bir adım öncesinden potansiyel koordinatları denemeye devam edeceğiz.

Vurgulanan çeşitli bileşen parçaları ile kod şöyle görünür:

Yürütme yolları vurgulanmış kaynak kodu

*Alanın genişliğini ve yüksekliğini okuyun ve 0geri izleme konumundan ziyade potansiyel bir yolu belirtmek için başlangıç ​​koordinatlarını bir tür işaretleyicisiyle birlikte itin . Basit bir komutla geri döndürülen geri
*izleme konumlarını ( 1tür işaretçisi ile gösterilir) kontrol edin p, çünkü bunlar oyun alanına bir boşluk yazmak için gereken tam formatta saklanır.
*Koordinatların hala oyun alanının içinde olup olmadığını kontrol edin. Menzil dışındaysa, bir sonraki potansiyel koordinatları denemek için bunları yığından çıkarın ve geri döngü yapın.
*Menzil içinde iseler, bir sonraki adımın yeri olan yığından sonraki iki değeri alın (bunu izleyen testte gereklidir).
*Koordinatların yolun mevcut bir segmentiyle temas edip etmeyeceğini kontrol edin. Bir önceki adımın yeri bu kontrolden açıkça göz ardı edilmiştir.
*Tüm testler başarılı olursa, #oyun alanına a yazın ve hedef konuma ulaşıp ulaşmadığımızı kontrol edin.
*Varsa, son yolu yazın *ve çıkın.
*Aksi takdirde, koordinatları 1daha sonra geriye doğru izlemek için bir tür işaretleyiciyle yığına kaydedin .
*Bu, yakında ihtiyaç duyacağımız rastgele bir sayı hesaplaması ile kesilir.
*Geçerli konumdan ulaşılabilecek dört potansiyel hedefi itin. Rastgele sayı, itildikleri sırayı ve dolayısıyla izlenecekleri sırayı belirler.
* Ana döngünün başlangıcına geri sarın ve yığındaki sonraki değerleri işleyin.


2
Kutsal inek. Açıklama?
Rɪᴋᴇʀ

@EasterlyIrk Ödül için teşekkürler. Çok takdir edilmektedir.
James Holderness

Yararlı sevindim!
Rɪᴋᴇʀ

2

QBasic, 259 bayt

Eminim aşk 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
?"#"

Temel strateji: Her adımda, a'yı #geçerli konuma yazdırın ve rastgele bir yönde hareket edin. Bir dizia0'lar ve 1'ler nerede olduğumuzu izler. Taşıma yasalsa ve bizi uç noktaya götürürse GOTO 9, döngüden çıkmak ve finali yazdırmak için #. Aksi takdirde, hareket yasal ise, başka bir adım atın. Aksi takdirde, ekranı temizleyin ve baştan başlayın (bir geri izleme algoritmasını kodlamaktan çok daha golfçü!).

QB64'te dizüstü bilgisayarımda test edildiğinde, bu genellikle 9, 9beş saniye veya daha kısa sürede sonuç verir . 10, 10Üç ila 45 saniye arasında herhangi bir yere ulaştı . Teorik olarak, tüm yasal yollar sıfır olmayan bir olasılığa sahiptir, ancak büyük eğrilere sahip bir yol olasılığı kaybolarak küçüktür. Gerçi zaman zaman bir veya iki küçük eğri ile yollar gördüm:

Örnek yol

İsteksiz versiyon ve / veya derinlemesine açıklama istek üzerine sağlanır.


2

R, 225 bayt

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

Açıklama:

Kenarlarda rastgele ağırlıklarla düzenli (kafes) [x * y] yönlendirilmemiş bir grafik üretiyoruz, sonra baştan sona en kısa yolu buluyoruz. Bununla birlikte, oluşturulan yolda, ikiden fazla komşu içeren hücreler olabilir:

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

Bu yüzden en kısa yol algoritmasını iki kez uygulamalıyız. İkinci kez, mevcut bulunan yoldaki 0 ​​hariç tüm ağırlıkları 1 olarak ayarladık;

sonuç

#
#
### 
  # 
  #
  ###

Ungolfed:

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 bayt

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>

Expanation: #s, önce bir genişlik ilk arama kullanılarak alanda bir yol bulunana kadar diziye rastgele yerleştirilir; birincisi ve dolayısıyla en kısa olanı, böyle bir yol çıkarılır; bu yolun kendisiyle kesişmediğini garanti eder. Özellikle daha büyük alanlar için bir yol bulunmadan önce JS motorunun yığınını aşmanın mümkün olduğunu unutmayın. Ungolfed:

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');
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.