หอคอยแห่งแก้ฮานอย


10

สำหรับการอ้างอิงถึงหอคอยแห่งฮานอยไม่ว่าจะเป็น Google หรือดูที่หน้าWikipedia

รหัสของคุณควรจะสามารถทำ 2 สิ่งและมีดังต่อไปนี้:

  • ยอมรับอินพุตของผู้ใช้ที่ระบุจำนวนแผ่นที่จุดเริ่มต้นของหอคอยฮานอย
  • สร้างผลลัพธ์ในแบบที่คุณเลือก (ตราบใดที่มันมีเหตุผลอย่างใด) เพื่อแสดงวิธีแก้ปริศนาทาวเวอร์

ตัวอย่างของเอาต์พุตโลจิคัลจะเป็นดังต่อไปนี้ (ใช้การเริ่มดิสก์ 4 ตัว):

L1L2C1L1R-2R-1L1L2C1C-1R-2C1L1L2C1

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

กฎไปยังหอคอยแห่งฮานอยง่าย:

  • สามารถย้ายดิสก์ได้ครั้งละหนึ่งดิสก์เท่านั้น
  • การย้ายแต่ละครั้งประกอบด้วยการเอาดิสก์บนจากหมุดหนึ่งและเลื่อนไปยังหมุดอื่นบนดิสก์อื่นที่อาจมีอยู่แล้วบนหมุดนั้น
  • ห้ามวางดิสก์ไว้บนดิสก์ที่เล็กกว่า

ดิสก์เริ่มต้นที่หมุดซ้ายสุดที่ใหญ่ที่สุดที่ด้านล่างเล็กที่สุดที่ด้านบนตามธรรมชาติ


เราจำเป็นต้องแก้หอคอยขนาดใหญ่โดยพลการหรือว่ามีข้อ จำกัด บางอย่างที่เราสามารถคาดเดาได้เช่นดิสก์ 10, 100, 1k, 1M หรือไม่?
ไม่ทราบผู้ใช้

@ userunknown ถ้าฉันเป็นคุณฉันจะไม่กังวลมากเกินไปเกี่ยวกับจำนวนที่มากเป็นพิเศษ แต่ฉันจะบอกว่าจำนวนดิสก์สูงสุดที่โปรแกรมของคุณสามารถจัดการควรถูก จำกัด ด้วยความจุของหน่วยความจำของคอมพิวเตอร์หรือขีด จำกัด การโทรซ้อน ( สิ่งเดียวกันฉันเดาเนื่องจากหน่วยความจำเป็นคำทั่วไปสวย) อย่าปล่อยให้ตัวเลขที่สูงตามอำเภอใจทำให้คุณตกใจเมื่อส่งรหัสของคุณ หากวิธีการแก้ปัญหาของคุณเป็นความคิดสร้างสรรค์ แต่สามารถจัดการดิสก์จำนวนมากได้ฉันก็ยังคงให้เครดิตคุณอยู่
Carter Pape

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

คำตอบ:


2

Husk , 5 ไบต์

↑≠⁰İr

ลองออนไลน์!
แต่ละอันnในเอ้าท์พุทแสดงถึงการเคลื่อนย้ายดิสก์nไปยังหมุดที่มีอยู่ถัดไป

คำอธิบาย

   İr   The ruler sequence [0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, ...]
↑       Take while...
 ≠⁰     ... not equal to the input.

7

Python 76 ตัวอักษร

def S(n,a,b):
 if n:S(n-1,a,6-a-b);print n,a,b;S(n-1,6-a-b,b)
S(input(),1,3)

ตัวอย่างเช่นสำหรับ N = 3 จะส่งคืน:

1 1 3  (move disk 1 from peg 1 to peg 3)
2 1 2  (move disk 2 from peg 1 to peg 2)
1 3 2  (move disk 1 from peg 3 to peg 2)
3 1 3  ...
1 2 1
2 2 3
1 1 3

ฉันรู้ว่าฉันมาช้าไปนิดหน่อย แต่เกมนี้มีทั้งหมด 13 ตัวอักษร: tio.run/##K6gsycjPM/r/…
JayCe

6

Perl - 54 ตัวอักษร

for(2..1<<<>){$_--;$x=$_&-$_;say(($_-$x)%3,($_+$x)%3)}

ทำงานด้วยperl -M5.010และป้อนจำนวนแผ่นดิสก์ใน stdin

รูปแบบผลลัพธ์:

หนึ่งบรรทัดต่อการย้ายตัวเลขตัวแรกคือจากหมุดหลักที่สองคือหมุด (เริ่มต้นจาก 0)

ตัวอย่าง:

02 -- move from peg 0 to peg 2
01
21
02
10
12
02

บันทึก 5 ตัวอักษรโดยลบวงเล็บปีกกา $x=--$_&-$_,say(($_-$x)%3,($_+$x)%3)for 2..1<<<>
marinus

5

GolfScript ( 31 25 24 ตัวอักษร)

])~{{~3%}%.{)3%}%2,@++}*

ด้วยความขอบคุณจาก Ilmari Karonen ที่ชี้ให้เห็นว่าต้นฉบับtr/ พีชคณิตของฉันจะสั้นลง 6 ตัวอักษร ด้วยการย่อยสลายมันเป็นผลคูณสองพีชคณิตฉันสามารถประหยัดได้อีกหนึ่งอย่าง

โปรดทราบว่าการแยก3%ความยาวเพิ่มขึ้นออกจากตัวละครตัวหนึ่ง

])~{{~}%.{)}%2,@++}*{3%}%

บางคนมีรูปแบบผลลัพธ์ที่ซับซ้อนจริงๆ เอาต์พุตนี้หมุดถูกย้ายจาก (หมายเลข 0, 1, 2) และหมุดย้ายไป สเป็คไม่ได้บอกว่าหมุดจะย้ายไปไหนดังนั้นมันจึงย้ายไปที่หมุด 1

เช่น

$ golfscript hanoi.gs <<<"3"
01021201202101

ไม่ต้องสงสัยเลยว่าตรรกะเดียวกันใน sed นั้นยิ่งสั้นลง แต่ความสามารถของ sed ของฉันไม่ได้ขึ้นอยู่กับมัน
Peter Taylor

1
คุณสามารถทำได้ใน 25 ตัวอักษร:])~{.{3^3%}%2,@{2\-}%++}*
Ilmari Karonen

3

Perl, 75 79ตัวอักษร

รูปแบบเอาต์พุตทั้งหมดของ Keith Randall ขโมยทั้งหมด:

sub h{my($n,$p,$q)=@_;h($n,$p^$q^h($n,$p,$p^$q),$q*say"@_")if$n--}h pop,1,3

วิงวอนด้วยสำหรับ-M5.010say

(ฉันคิดว่าสิ่งนี้สามารถปรับปรุงได้ถ้าคุณสามารถหาวิธีที่จะใช้ประโยชน์จากค่าส่งคืนของฟังก์ชั่นแทนการระงับมัน)


sayคำแนะนำ[หุ้น "ใช้เพียง"]
JB

โอเค - แต่ฉันจะไม่ต้องรวมค่าใช้จ่ายของการเปิดใช้งานคุณลักษณะ 5.10 เทียบกับจำนวนถ่านของฉันหรือไม่
breadbox

1
คุณจะ - แต่มันฟรี เพียงแค่จดบันทึกวิธีการเรียกใช้โปรแกรมของคุณเพื่อให้คนที่ไม่เชี่ยวชาญในภาษาที่เฉพาะเจาะจงสำหรับการภาวนา Perl สามารถให้โอกาสได้
JB

ขอบคุณสำหรับลิงค์; ฉันกำลังมองหาสิ่งนั้นก่อนหน้านี้
breadbox

3

SML, 63

fun f(0,_,_)=[]|f(n,s,t)=f(n-1,s,6-s-t)@[n,s,t]@f(n-1,6-s-t,t);

ฟังก์ชั่นการโทรf(n,s,t)ด้วย:

  • จำนวนดิสก์
  • จุดเริ่มต้นของ
  • จุดเป้าหมาย

2

Bash (64 ตัวอักษร)

t(){ tr 2$1 $12 <<<$s;};for((i=$1;i--;))do s=`t 1`01`t 0`;done;t

การโพสต์นี้แม้จะเป็นมากกว่าสองเท่าของความยาวของ GolfScript หนึ่งเพราะผมชอบนำมาใช้ใหม่ของการทำหน้าที่เป็นtecho $s


2

สกาลา, 92 88 87 ตัวอักษร

def?(n:Int,a:Int,b:Int){if(n>0){?(n-1,a,a^b)
print(n,a,b);?(n-1,a^b,b)}};?(readInt,1,3)

รูปแบบเอาต์พุต

พูดจำนวนดิสก์ = 3 แล้ว

(1,1,3)(2,1,2)(1,3,2)(3,1,3)(1,2,1)(2,2,3)(1,1,3) (disk number,from peg, to peg)
                                                   \---------------------------/       
                                                            Move 1              ... Move n

การใช้งานที่ดีของ xor
Peter Taylor

2

C, 98 92 87 ตัวอักษร

ใช้อัลกอริทึมเล็กน้อยที่สุด
เอาต์พุตอยู่ในรูปแบบab ab abที่แต่ละคู่หมายถึง "ย้ายแผ่นดิสก์ด้านบนจาก peg a ไปยัง peg b"
แก้ไข : ย้ายตอนนี้ถูกเข้ารหัสใน hex - 0x12 หมายถึงย้ายจากหมุด 1 ไปตรึง 2 บันทึก Characeters บางส่วน
แก้ไข : อ่านตัวเลขจาก stdin แทนที่จะเป็นพารามิเตอร์ สั้น
ตัวอย่าง:
% echo 3 | ./hanoi
13 12 32 13 21 23 13

n;
h(d){n--&&h(d^d%16*16,printf("%02x ",d,h(d^d/16))),n++;}
main(){scanf("%d",&n);h(19);}

มีคนอธิบายไวยากรณ์ของเนื้อความของฟังก์ชัน h () - โดยเฉพาะอย่างยิ่งอาร์กิวเมนต์สองตัวที่ชัดเจนในการเรียกแบบเรียกซ้ำ (d ^ d% 16 * 16 และ printf (... )) และการดำเนินการครั้งสุดท้ายดูเหมือนจะสิ้นสุดลง จากความรู้ของฉันฟังก์ชั่นนั้นมีข้อผิดพลาดทางไวยากรณ์สองข้อ แต่ฉันรู้แล้วว่ามันสร้าง (หลังจากรวม stdio) และดำเนินการอย่างถูกต้อง
Griffin

1
เป็นไปได้ที่จะผ่านพารามิเตอร์มากกว่าฟังก์ชันที่ต้องการ ค่านิยมของพวกเขาไม่มีที่ไหนเลย h(x,printf(...))เป็นวิธีที่จะโทรหาprintfก่อนหน้าhนี้ สุดท้ายn++ทำหลังจากhผลตอบแทนภายใน n--โดยจะใช้เพื่อยกเลิกการเริ่มต้น
ugoren

ขอบคุณที่เหมาะสม (จุดประสงค์ของ n ++ นั้นชัดเจน) เหตุใดจึงไม่มีเครื่องหมายอัฒภาคมาก่อน n ++ แทนเครื่องหมายจุลภาคหรือสร้างความแตกต่าง
Griffin

@Griffin จริง ๆ แล้ว;จะเหมือนกันที่นี่ ,มักจะมีประโยชน์ (เช่นif(x)a,b;แทนที่if(x){a;b;}) แต่ไม่มีประโยชน์ที่นี่
ugoren

2

เยลลี่ 5 ไบต์

2*Ṗọ2

ลองออนไลน์!

0ย้ายดิสก์ที่เล็กที่สุดหนึ่งช่องว่างไปทางขวา (ตัดกลับไปที่จุดเริ่มต้นหากจำเป็น)
1ย้ายดิสก์ที่เล็กที่สุดที่สองไปยังคอลัมน์กฎหมายอื่น ๆ เท่านั้นที่จะ
2ย้ายดิสก์ที่เล็กที่สุดที่สามไปยังคอลัมน์กฎหมายอื่น ๆ เท่านั้น
เป็นต้น

ขั้นตอนวิธี

เราสามารถเห็นทางออกของปัญหาหอคอยแห่งฮานอยแบบวนซ้ำ หากต้องการย้ายสแต็กขนาดnจากAถึงBให้ย้ายสแต็กขนาดn -1 จากAถึงCจากนั้นดิสก์ขนาดnจากAถึงBจากนั้นย้ายสแต็กขนาดn -1 จากBไปยัง C สิ่งนี้สร้างรูปแบบของแบบฟอร์มต่อไปนี้ (ในรูปแบบเอาต์พุตที่ใช้โดยโปรแกรมนี้):

0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2 …

เราสามารถสังเกตได้ว่าลำดับนี้คือA007814บน OEIS ความหมายที่เป็นไปได้ของลำดับคือ " k (ตาม 1) ของลำดับคือจำนวนของศูนย์ในตอนท้ายของหมายเลขkเมื่อมันถูกเขียนในไบนารี" และนี่คือสิ่งที่โปรแกรมคำนวณ

คำอธิบาย

อันดับแรกเราคำนวณจำนวนการเคลื่อนไหวในคำตอบ 2 n -1 มันสั้นกว่าที่จะคำนวณการเคลื่อนที่หนึ่งครั้งและทิ้งไว้ในภายหลังดังนั้นนี่คือ2*2 คือพลังของบางสิ่ง (อินพุตเดียวที่เราได้ทำไปคืออาร์กิวเมนต์บรรทัดคำสั่งดังนั้นค่าเริ่มต้นจะถูกใช้)

ต่อไปเราใช้บิวด์อินเจลลี่สำหรับคำนวณจำนวนศูนย์ในตอนท้ายของตัวเลขในฐานb ; ว่า ในขณะที่เรากำลังคำนวณเลขฐานสองก็ สิ่งที่เราต้องทำคือการใช้บิวด์อินนี้กับตัวเลขตั้งแต่ 1 ถึง 2bọ2 n -1

มีวิธีง่าย ๆ สองวิธีในการวนซ้ำในช่วงของตัวเลขในเยลลี่และRและความพยายามก่อนหน้านี้ของฉันเกี่ยวกับปัญหานี้ใช้หนึ่งในวิธีเหล่านี้ อย่างไรก็ตามในกรณีนี้มีความเป็นไปได้ที่จะสั้นลงเล็กน้อย: เมื่อกำหนดตัวเลขเป็นอินพุตจะช่วยให้คุณทำซ้ำที่หยุดองค์ประกอบหนึ่งสั้น (โดยทั่วไปคือบิวอินที่ใช้ในการประมวลผลทั้งหมด นั่นคือสิ่งที่เราต้องการในกรณีนี้ (เพราะ2*สร้างหนึ่งเอลเมนต์มากเกินไป) ดังนั้นการใช้มันเพื่อเชื่อมโยง2*และนำọ2ไปสู่2*Ṗọ2การแก้ปัญหาแบบ 5 ไบต์ให้กับเรา



1

Bash script, 100 96 chars

t(){ [[ $1<1 ]] && return
t $(($1-1)) $2 $(($2^$3))
echo $@
t $(($1-1)) $(($2^$3)) $3
}
t $1 1 3

รูปแบบออกเป็นเช่นเดียวกับคี ธ แรนดัลหนึ่งของ

1 1 3
2 1 2
1 3 2
3 1 3
1 2 1
2 2 3
1 1 3

แก้ไข : บันทึก 4 ตัวอักษรโดยความคิดเห็นของpeter


1
คุณสามารถเพิ่มช่องว่างและบันทึกสองสามตัวอักษรโดยสะท้อน$@
Peter Taylor

@PeterTaylor: จุดดี ให้ฉันอัปเดต
เจ้าชายจอห์นเวสลีย์

1

J, 23 ไบต์

โซลูชันเลขฐานสอง

2&(+/@:~:/\)@#:@i.@^~&2

วิธีนี้ใช้วิธีการนับเลขฐานสองที่อธิบายไว้ในวิดีโอนี้

ซึ่งก็คือว่าฉันสร้างเลขฐานสองจาก1ถึง2^nจากนั้นใช้ความยาว 2 และเปรียบเทียบแต่ละบิตกับบิตที่สอดคล้องกันของตัวเลขก่อนหน้านี้และตรวจสอบว่าพวกเขาไม่เท่ากัน จำนวนบิตที่ไม่เท่ากันคือเอาต์พุตสำหรับการย้ายนั้น

เอาต์พุตเช่นดิสก์ 3 แผ่นโดยที่ดิสก์ขนาดเล็กที่สุดมีป้ายกำกับ 1:

1 2 1 3 1 2 1

1 หมายถึง "ย้ายดิสก์ที่เล็กที่สุดหนึ่งหมุดขวา, วนกลับไปยังหมุดแรกถ้าจำเป็น"

nสำหรับวิธีอื่นnหมายถึง "ย้ายดิสก์nไปที่หมุดที่ถูกกฎหมาย" (จะมีหนึ่งแผ่นเสมอ)

ลองออนไลน์!

โซลูชันแบบเรียกซ้ำ

((],[,])$:@<:)`]@.(1=])

เอาต์พุตเช่นเดียวกับโซลูชันข้างต้น แต่ตรรกะที่นี่ทำให้ลักษณะการเรียกซ้ำของปัญหาชัดเจนขึ้น

การเห็นภาพต้นไม้เป็นสิ่งที่เน้นจุดนี้:

              4
             / \
            /   \
           /     \
          /       \
         /         \
        /           \
       /             \
      3               3      
     / \             / \    
    /   \           /   \
   /     \         /     \ 
  2       2       2       2  
 / \     / \     / \     / \
1   1   1   1   1   1   1   1

ลองออนไลน์!


1
ลักษณะที่บังเอิญของการส่งคำตอบของคุณเกิน 5 ปีหลังจากคำถามเดิมถูกโพสต์ภายในชั่วโมงเดียวกับที่ฉันกลับไปทบทวนคำตอบสำหรับคำถามนี้ที่ฉันส่งมาเมื่อ 5 ปีที่แล้ว ... ว้าว +1
Carter Pape



0

R , 73 ไบต์

วาง R บนแผนที่ แรงบันดาลใจจาก [คำตอบของ Keith Randall] [1] ด้วยอินพุตแบบง่ายพิมพ์เฉพาะสิ้นสุดและเริ่มต้นหมุดเพื่อบันทึก 2 ไบต์ 0 หมุดยังจัดทำดัชนีด้วย

f=function(n,s=0,e=2){if(n){f(n-1,s,3-s-e)
print(c(s,e))
f(n-1,3-s-e,e)}}

ลองออนไลน์!


0

JavaScript (ES6), 45b

h=(n,f,a,t)=>n?h(--n,f,t,a)+f+t+h(n,a,f,t):''

เช่นการโทรh(4, 'A', 'B', 'C')(ย้าย 4 แผ่นจาก peg A ไปยังตรึง C โดยใช้ Peg เสริม B)

ผลตอบแทน'ABACBCABCACBABACBCBACABCABACBC'(ย้ายแผ่นดิสก์จากหมุด A ไปยังหมุด B, ย้ายแผ่นดิสก์จากหมุด A ไปยังหมุด C, ย้ายแผ่นดิสก์จากหมุด B ไปยังหมุด C ฯลฯ )


1
ดี ฉันสงสัยว่าพารามิเตอร์ f, a, t ควรมีค่าเริ่มต้นรวมอยู่ในการกำหนดฟังก์ชันหรือไม่ มิฉะนั้นการส่งอาจรวมถึงข้อมูลโดยพลการใน args เพิ่มเติม ฉันเป็นมือใหม่ดังนั้นคนที่มีประสบการณ์มากควรแนะนำ
John Rees
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.