{{위키데이터 속성 추적}}
{{구별|AON 하노이 랜드마크 타워}}
[[파일:Tower_of_Hanoi.jpeg|300px|섬네일|하노이의 탑]]
'''하노이의 탑'''(Tower of Hanoi)은 퍼즐의 일종이다. 세 개의 기둥과 이 기둥에 꽂을 수 있는 크기가 다양한 원판들이 있고, 퍼즐을 시작하기 전에는 한 기둥에 원판들이 작은 것이 위에 있도록 순서대로 쌓여 있다.

게임의 목적은 다음 세 가지 조건을 만족시키면서, 한 기둥에 꽂힌 원판들을 그 순서 그대로 다른 기둥으로 옮겨서 다시 쌓는 것이다.
# 한 번에 한개의 원판만 옮길 수 있다.
# 가장 위에 있는 원판만 이동할 수 있다.
# 큰 원판이 작은 원판 위에 있어서는 안 된다.

[[파일:Tower of Hanoi 4.gif|300px|섬네일|하노이의 탑의 원리(애니메이션)]]
하노이의 탑 문제는 [[재귀 호출]]을 이용하여 풀 수 있는 가장 유명한 예제 중의 하나이다. 그렇기 때문에 프로그래밍 수업에서 [[알고리즘]] 예제로 많이 사용한다.
일반적으로 원판이 ''n''개 일 때, 2<sup>''n''</sup> -1번의 이동으로 원판을 모두 옮길 수 있다(2<sup>''n''</sup> − 1는 [[메르센 수]]라고 부른다).

한 번의 실수 없이 64개의 원판을 옮기는 데 2<sup>64</sup> - 1 = 18,446,744,073,709,551,615번(약 1.84 × 10<sup>19</sup>)을 움직여야 하고, 1초당 한 번 원판을 움직일 때 584,554,049,253년(1년 = 365.2425일)이 걸린다. 이는 우주의 나이인 138억 년의 42.4배이다.<ref>{{서적 인용|last=Moscovich |first=Ivan |authorlink=Ivan Moscovich |title=1000 playthinks: puzzles, paradoxes, illusions & games |publisher=Workman |year=2001 |isbn=978-0-7611-1826-8 }}</ref>

== 유래 ==
하노이의 탑은 프랑스의 수학자인 [[에두아르 뤼카]](Édouard Lucas)가 클라우스 교수(professeur N. Claus)라는 필명으로 1883년에 발표하였다.<ref>{{서적 인용| title=The Tower of Hanoi – Myths and Maths | isbn= 978-3034802369| last1= Hinz| first1= Andreas M.| last2= Klavžar| first2= Sandi| last3= Milutinović| first3= Uroš| last4= Petr| first4= Ciril| date= 2013-01-31}}</ref> 1년 후 드 파르빌(Henri de Parville)은 Claus가 Lucas의 [[애너그램]]임을 밝히면서 다음과 같은 이야기로 하노이의 탑을 소개하였다.

:"[[인도]] [[베나레스]]에 있는 한 사원에는 세상의 중심을 나타내는 큰 [[돔 (건축)|돔]]이 있고 그 안에 세 개의 다이아몬드 바늘이 동판 위에 세워져 있습니다. 바늘의 높이는 1 [[큐빗]]이고 굵기는 벌의 몸통만 합니다. 바늘 가운데 하나에는 신이 64개의 순금 원판을 끼워 놓았습니다. 가장 큰 원판이 바닥에 놓여 있고, 나머지 원판들이 점점 작아지며 꼭대기까지 쌓아 있습니다. 이것은 신성한 [[브라흐마]]의 탑입니다. 브라흐마의 지시에 따라 승려들은 모든 원판을 다른 바늘로 옮기기 위해 밤낮 없이 차례로 제단에 올라 규칙에 따라 원판을 하나씩 옮깁니다. 이 일이 끝날 때, 탑은 무너지고 세상은 종말을 맞이하게 됩니다."<ref>{{서적 인용|last=Spitznagel |first=Edward L. |title=Selected topics in mathematics |year=1971 |publisher=Holt, Rinehart and Winston |page=[https://archive.org/details/selectedtopicsin0000spit/page/137 137] |isbn=978-0-03-084693-9 |url-access=registration |url=https://archive.org/details/selectedtopicsin0000spit/page/137 }}</ref>

이후 [[라우즈 볼]], [[마틴 가드너|가드너]] 등이 하노이의 탑을 소개하면서 널리 알려졌다.

== 소스 코드 ==
이것은 각각의 수를 구하는 컴퓨터 프로그램 등의 실행어에 대한 것이다.

=== [[OCaml]] ===
<syntaxhighlight lang="ocaml">
let rec move_tower n a b c = match n with
	| 1 -> [(a,c)]
	| _ -> (move_tower (n-1) a c b) @ (move_tower 1 a b c) @ (move_tower (n-1) b a c);;
</syntaxhighlight>

=== [[리스프|Lisp]] ===
<syntaxhighlight lang="lisp">
(defun hanoitowers (disc src aux dst)
  (cond ((> disc 0)
	 (hanoitowers (- disc 1) src dst aux)
	 (princ (list "Move" disc "from" src "to" dst))
</syntaxhighlight>

=== [[파스칼 (프로그래밍 언어)|Pascal]] ===

<syntaxhighlight lang="pascal">
procedure Hanoi(n: integer; from, dest, by: char);
Begin
    if (n=1) then
        writeln('Move the plate from ', from, ' to ', dest)
    else begin
        Hanoi(n-1, from, by, dest);
        Hanoi(1, from, dest, by);
        Hanoi(n-1, by, dest, from);
    end;
End;
</syntaxhighlight>
=== [[C (프로그래밍 언어)|C++]] ===
<syntaxhighlight lang="cpp" line="1">
#include <iostream>
using namespace std;

void move(int from, int to)
{
    cout << from << " -> " << to << '\n';
}

void hanoi(int n, int from, int by, int to)
{
    if(n == 0) return;
    hanoi(n - 1, from, to, by);
    move(from, to);
    hanoi(n - 1, by, from, to);
}

</syntaxhighlight>

=== [[파이썬]] ===
<syntaxhighlight lang="python">
def hanoi(number_of_disks_to_move, from_, to_, via_):
    if number_of_disks_to_move == 1:
        print(from_, "->", to_)
    else:
        hanoi(number_of_disks_to_move-1, from_, via_, to_)
        print(from_, "->", to_)
        hanoi(number_of_disks_to_move-1, via_, to_, from_)
</syntaxhighlight>

=== [[Visual Prolog]] ===
<syntaxhighlight lang="visualprolog">
class hanoi
   predicates
       hanoi : (unsigned N).
end class hanoi

implement hanoi
   domains
       pole = string.

   clauses
       hanoi(N) :- move(N, "left", "centre", "right").

   class predicates
       move : (unsigned N, pole A, pole B, pole C).
   clauses
       move(0, _, _, _) :- !.
       move(N, A, B, C) :- 
           move(N-1, A, C, B),
           stdio::writef("move a disc from % pole to the % pole\n", A, C),
           move(N-1, B, A, C).
end implement hanoi

goal
   console::init(),
   hanoi::hanoi(4).
</syntaxhighlight>

=== [[스위프트 (프로그래밍 언어)|Swift]] ===
<syntaxhighlight lang="swift">
import Foundation

func hanoi(_ n: Int, from a: Int, to b: Int, by c: Int) {
    if n==1 {
        print("Move 1 from \(a) to \(b)")
    }
    else {
        hanoi(n-1, from: a, to: b, by: c)
        print("Move \(n) from\(a) to\(b)")
        hanoi(n-1, from: c, to: b, by: a)
    }
}
</syntaxhighlight>

== 같이 보기 ==
* [[재귀 (컴퓨터 과학)]]

== 각주 ==
<references />

== 외부 링크 ==
{{위키공용분류}}
* {{매스월드|id=TowerofHanoi|title=Tower of Hanoi}}

{{전거 통제}}
{{토막글|컴퓨터 과학}}

[[분류:기계식 퍼즐]]