สร้างเส้นทางที่ไม่ตัดกันแบบ ASCII


18

รับอินพุตจำนวนเต็ม 2 ค่าแทนขนาดของเขตข้อมูลxและyส่งออกเส้นทางผ่านเขตข้อมูล

ตัวอย่างผลลัพธ์สำหรับ5, 4:

#    
#    
# ###
### #

เขตข้อมูลทั้งหมดคือ 5 คูณ 4 และมีเส้นทางที่ทำจาก hashmarks ที่ข้ามเขตข้อมูล

เส้นทางควรเริ่มที่มุมซ้ายบนเสมอและไปที่ด้านล่างขวา เส้นทางทั้งหมดควรถูกสุ่มทุกครั้งที่มีการเรียกใช้โปรแกรม ทุกเส้นทางที่ถูกต้องควรเป็นผลลัพธ์ที่เป็นไปได้

กฎสำหรับเส้นทางคือ:

  • ทำจาก hashmarks

  • ทุกแฮชจะเชื่อมต่อกับ 2 แฮชอื่น ๆ เท่านั้น (เช่นเส้นทางไม่ได้ตัดกันหรือวิ่งเคียงข้างกัน)

ช่องว่างที่ไม่แฮชสามารถเติมด้วยอักขระอื่น แต่ต้องสอดคล้องกัน (เช่นช่องว่างทั้งหมดระยะเวลาทั้งหมดเป็นต้น)

ตัวอย่าง:

2, 2

##
 #

3, 4

##
 ##
  #
  #

5, 5

#####
    #
    #
    #
    #

6, 5

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

7, 9

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

เส้นทางประเภทนี้คล้ายกับการเดินสุ่มด้วยตนเองที่หลีกเลี่ยงได้ แต่ไม่สามารถติดกับตัวเองได้ซึ่งแตกต่างจาก SAW ที่แท้จริง

ความต่อเนื่องของเส้นทางและการสัมผัสเส้นทางนั้นถูกกำหนดโดยไม่มีเส้นทแยงมุม


รูปแบบเอาต์พุต RBX.Lua ถูกต้องหรือไม่ ;)
devRicher

ถูกต้องหรือไม่หากตราบใดที่เส้นทางที่ถูกต้องทุกอันมีความน่าจะเป็นบวกที่ได้รับเลือกการกระจายความน่าจะเป็นโดยพลการ
ข้อผิดพลาด

@devRicher ใช่
Rɪᴋᴇʀ

@flawr ใช่นั่นถูกต้องแล้ว
2560

คำตอบ:


11

MATLAB, 316 305 300 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คำหลักและ hardcode ค่า, ประการที่สอง: ช่องว่างไม่ได้พิมพ์อย่างถูกต้องเช่นเดียวกับใน Matlab ฉันยังไม่ ตรวจสอบคำสั่ง convolution ของ 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,''];

โอ้และเช่นเคย:

Convolution คือกุญแจสู่ความสำเร็จ


19

Befunge ขนาด 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-+!#^_

ลองออนไลน์!

ดังที่ @flawr พูดถึงในคำตอบของ MATLAB อาจใช้เวลาสักครู่ถ้าขนาดของฟิลด์มีขนาดที่ไม่สำคัญ ในความเป็นจริงมันค่อนข้างง่ายที่จะเข้าไปในสถานการณ์ที่มันไม่คุ้มค่าที่จะต้องรอให้เสร็จเพราะคุณมีแนวโน้มที่จะรอจนกว่าจะหมดเวลา

เพื่อให้เข้าใจว่าทำไมสิ่งนี้ถึงเกิดขึ้นมันจะเป็นประโยชน์ในการดูโปรแกรมในขณะที่ทำงานในหนึ่งใน "visual debuggers" ของ Befunge เนื่องจากข้อมูลและรหัสเป็นสิ่งเดียวกันใน Befunge คุณจะได้เห็นเส้นทางที่มันเปลี่ยนแปลงตลอดเวลา ตัวอย่างเช่นต่อไปนี้เป็นภาพเคลื่อนไหวสั้น ๆ ที่แสดงให้เห็นว่าส่วนใดของการวิ่งบนเส้นทางที่ช้าอาจดูเหมือน

แอนิเมชันที่แสดงการสร้างเส้นทางทำให้ติดอยู่ที่มุมห้อง

เมื่ออัลกอริธึมตัดสินใจที่จะเลี้ยวไปทางซ้ายที่ด้านล่างของขอบเขตของสนามนั้นมันได้ประณามตัวเองไปตลอดชีวิตที่ไร้จุดหมาย จากจุดนั้นต้องทำตามทุกเส้นทางที่เป็นไปได้ในพื้นที่รั้วกั้นก่อนที่จะถอยออกมาและลองเลี้ยวไปทางขวา และจำนวนเส้นทางที่มีศักยภาพในกรณีเหล่านี้สามารถกลายเป็นทางดาราศาสตร์ได้อย่างง่ายดาย

Bottom line: หากดูเหมือนว่าจะใช้เวลานานอาจเป็นความคิดที่ดีที่จะยกเลิกการดำเนินการและเริ่มต้นใหม่อีกครั้ง

คำอธิบาย

นี่คืออัลกอริทึมแบบเรียกซ้ำโดยพยายามทุกเส้นทางที่เป็นไปได้ผ่านเขตข้อมูลและจากนั้นทำตามขั้นตอนที่คลี่คลายเมื่อใดก็ตามที่มันติดอยู่ เนื่องจาก Befunge ไม่มีแนวคิดเกี่ยวกับฟังก์ชั่นฟังก์ชันเรียกซ้ำจึงเป็นไปตามคำถาม แต่เราสามารถจำลองกระบวนการโดยติดตามสถานะบนสแต็ก

สิ่งนี้ทำงานโดยการเติมสแต็กด้วยพิกัดที่เป็นไปได้ที่เราอาจต้องการติดตาม จากนั้นเราจะดึงชุดหนึ่งออกมาจากสแต็กและตรวจสอบว่าเหมาะสมหรือไม่ (เช่นอยู่ในระยะและไม่ทับซ้อนกับพา ธ ที่มีอยู่) เมื่อเรามีจุดที่ดีแล้วเราก็เขียน#ลงในสนามเด็กเล่นที่สถานที่นั้นและเพิ่มรายละเอียดเหล่านั้นไปยังสแต็คในกรณีที่เราต้องการย้อนกลับในภายหลัง

จากนั้นเราจะเพิ่มพิกัดอีกสี่ชุดลงบนสแต็ก (ตามลำดับแบบสุ่ม) เพื่อระบุเส้นทางที่เป็นไปได้ที่เราสามารถรับได้จากที่ตั้งใหม่และข้ามกลับไปที่จุดเริ่มต้นของลูป หากไม่มีเส้นทางที่เป็นไปได้เราจะไปถึงจุดบนสแต็กที่เราบันทึกตำแหน่งที่#เราเขียนออกไปดังนั้นเราจะยกเลิกขั้นตอนนั้นและลองใช้พิกัดที่มีศักยภาพจากขั้นตอนเดียวก่อน

นี่คือรหัสที่มีลักษณะเหมือนกับส่วนต่าง ๆ ที่ไฮไลต์ไว้:

ซอร์สโค้ดที่มีไฮไลต์พา ธ การเรียกใช้งาน

* * * *อ่านความกว้างและความสูงของสนามและกดพิกัดเริ่มต้นพร้อมกับ0เครื่องหมายประเภทเพื่อระบุเส้นทางที่เป็นไปได้แทนที่จะเป็นตำแหน่งย้อนรอย
* * * *ตรวจสอบสถานที่ย้อนรอย (ระบุโดยตัวระบุ1ประเภท) ซึ่งเปลี่ยนกลับด้วยpคำสั่งง่าย ๆเนื่องจากตำแหน่งเหล่านั้นถูกจัดเก็บในรูปแบบที่แน่นอนที่จำเป็นในการเขียนช่องว่างกลับเข้าไปในสนามเด็กเล่น
* * * *ตรวจสอบว่าพิกัดยังคงอยู่ในสนามแข่งขันหรือไม่ หากอยู่นอกระยะให้ปล่อยจากสแต็กและวนกลับเพื่อลองพิกัดที่มีศักยภาพถัดไป
* * * *หากอยู่ในช่วงรับค่าสองค่าถัดไปจากสแต็กซึ่งเป็นตำแหน่งของขั้นตอนก่อนหน้า (จำเป็นในการทดสอบที่ตามหลังนี้)
* * * *ตรวจสอบว่าพิกัดกำลังเข้ามาติดต่อกับส่วนที่มีอยู่ของเส้นทาง ที่ตั้งของขั้นตอนก่อนหน้านี้จะถูกละเว้นอย่างชัดเจนจากการตรวจสอบนี้
* * * *หากการทดสอบทั้งหมดสำเร็จให้เขียน a #playfield และตรวจสอบว่าเราไปถึงสถานที่ปลายทางแล้วหรือยัง
* * * *หากเรามีให้เขียนเส้นทางสุดท้าย* * * *และออก
* * * *มิฉะนั้นให้บันทึกพิกัดลงบนสแต็กด้วยตัว1ทำเครื่องหมายชนิดสำหรับการย้อนรอยในภายหลัง
* * * *สิ่งนี้ถูกขัดจังหวะด้วยการคำนวณตัวเลขแบบสุ่มซึ่งเราจะต้องใช้ในไม่ช้า
* * * *กดสี่จุดหมายที่เป็นไปได้ที่สามารถเข้าถึงได้จากตำแหน่งปัจจุบัน หมายเลขสุ่มจะเป็นตัวกำหนดลำดับการผลักของพวกเขาและลำดับที่จะถูกติดตาม
* * * * ห่อกลับไปที่จุดเริ่มต้นของลูปหลักและประมวลผลค่าถัดไปบนสแต็ก


2
วัวศักดิ์สิทธิ์ คำอธิบาย?
Rɪᴋᴇʀ

@EasterlyIrk ขอบคุณสำหรับความกรุณา มันเป็นที่นิยมมาก
James Holderness

ดีใจที่มันมีประโยชน์!
Rɪᴋᴇʀ

2

QBasic ขนาด 259 ไบต์

ฉันแน่ใจว่ารัก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
?"#"

กลยุทธ์พื้นฐาน: ในแต่ละขั้นตอนให้พิมพ์ a #ไปยังตำแหน่งปัจจุบันและเคลื่อนที่ไปในทิศทางที่สุ่ม อาเรย์aของ 0s และ 1s จะติดตามว่าเราเคยไปที่ไหน หากการย้ายเป็นกฎหมายและพาเราไปยังปลายทางที่จะออกจากวงและพิมพ์สุดท้ายGOTO 9 #มิฉะนั้นหากการเคลื่อนไหวนั้นถูกกฎหมายให้ทำขั้นตอนอื่น อื่น ๆ ล้างหน้าจอและเริ่มต้นใหม่ (มากนักกอล์ฟกว่าการเข้ารหัสอัลกอริทึมย้อนรอย!)

ทดสอบบนแล็ปท็อปของฉันใน QB64 สิ่งนี้โดยทั่วไปจะให้ผลลัพธ์9, 9ในห้าวินาทีหรือน้อยกว่า ระยะเวลาในการ10, 10ดำเนินการระหว่างสามถึง 45 วินาที ในทางทฤษฎีเส้นทางทางกฎหมายทั้งหมดมีความน่าจะเป็นที่ไม่เป็นศูนย์ แต่ความน่าจะเป็นของเส้นทางที่มีเส้นโค้งขนาดใหญ่นั้นเล็กมาก ฉันเคยเห็นเส้นทางที่มีโค้งเล็ก ๆ หนึ่งหรือสองครั้งเป็นครั้งคราว:

เส้นทางตัวอย่าง

มีเวอร์ชันที่ไม่ดีและ / หรือคำอธิบายเชิงลึกตามคำขอ


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

คำอธิบาย:

เราสร้างกราฟแบบไม่ระบุทิศทาง (x) y [x * y] แบบไม่ระบุทิศทางพร้อมด้วย weigths แบบสุ่มบนขอบจากนั้นเราจะพบเส้นทางที่สั้นที่สุดตั้งแต่ต้นจนจบ อย่างไรก็ตามในเส้นทางที่สร้างขึ้นอาจมีเซลล์ที่มีมากกว่าสอง neigbors:

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

ดังนั้นเราควรใช้อัลกอริธึมพา ธ ที่สั้นที่สุดสองครั้ง ในครั้งที่สองเราตั้งค่าน้ำหนักทั้งหมดเป็น 1 ยกเว้นน้ำหนักที่อยู่ในเส้นทางที่พบปัจจุบันที่ตั้งค่าเป็น 0

ผลลัพธ์

#
#
### 
  # 
  #
  ###

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 ไบต์

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>

Exposition: #s จะถูกวางแบบสุ่มในอาร์เรย์จนกว่าจะพบเส้นทางผ่านฟิลด์โดยใช้การค้นหาแบบกว้างแรก แรกและสั้นที่สุดดังนั้นเส้นทางดังกล่าวจะถูกส่งออก; สิ่งนี้รับประกันว่าเส้นทางจะไม่ตัดกัน โปรดทราบว่าโดยเฉพาะอย่างยิ่งสำหรับเขตข้อมูลขนาดใหญ่เป็นไปได้ที่จะเกินกองเครื่องยนต์ของ JS ก่อนที่จะพบเส้นทาง 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');
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.