Playground Component

Tower Of
Hanoi Visualizer

An interactive Tower of Hanoi visualization that animates recursive disk moves between source, auxiliary, and destination rods.

Tower Of Hanoi Visualizer

Tower of Hanoi Visualizer

Number of Disks:

Status

Idle

Moves

0

Total Moves

0

Disks

5

Tower 1
Tower 2
Tower 3
5
4
3
2
1

Copy Code

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tower of Hanoi Visualizer</title>
<style>
:root{--bg:#090909;--panel:#111;--gold:#f4c430;--gold-dark:#b88700;--text:#f5f5f5;--border:#2f2f2f}*{box-sizing:border-box}body{margin:0}.hanoi-visualizer{min-height:100vh;padding:40px;background:radial-gradient(circle at top,#1a1505 0%,#090909 40%);color:var(--text);font-family:Poppins,Arial,sans-serif}.hanoi-visualizer h2{text-align:center;font-size:3rem;color:var(--gold);margin:0 0 35px;text-shadow:0 0 24px rgba(244,196,48,.25)}.controls{display:flex;justify-content:center;align-items:center;gap:15px;flex-wrap:wrap;margin-bottom:35px}.disk-count-control{display:flex;align-items:center;gap:10px;padding:10px 16px;border-radius:12px;border:1px solid #555;background:#151515;color:var(--gold)}.disk-count-control span{font-size:15px;color:#ccc;font-weight:600}.disk-count-control input{width:50px;padding:8px;border-radius:8px;border:1px solid #444;background:#0e0e0e;color:var(--gold);text-align:center;font-size:16px;outline:none}.controls button{padding:14px 22px;border:0;border-radius:12px;cursor:pointer;font-weight:600;font-size:15px;background:linear-gradient(180deg,#ffd54d,#d9a900);color:#111;transition:.25s}.controls button:hover{transform:translateY(-2px)}.controls button:disabled{opacity:.5;cursor:not-allowed;transform:none}.stats{width:100%;max-width:900px;margin:auto;margin-bottom:40px;display:grid;grid-template-columns:repeat(4,1fr);gap:18px}.stat-box{background:#151515;border:1px solid #2b2b2b;border-radius:14px;padding:18px;text-align:center}.stat-box h4{margin:0;color:#999;font-size:.9rem}.stat-box p{margin:8px 0 0;color:var(--gold);font-size:1.4rem;font-weight:bold}.towers-frame{max-width:1100px;margin:auto;border:1px solid var(--border);border-radius:20px;background:#0c0c0c;padding:20px}.towers{position:relative;width:100%}.pole{position:absolute;bottom:12px;width:6px;border-radius:4px;background:linear-gradient(180deg,#ffd54d,#b88700);box-shadow:0 0 10px rgba(244,196,48,.35);transform:translateX(-50%)}.baseline{position:absolute;left:2%;right:2%;bottom:8px;height:4px;border-radius:4px;background:linear-gradient(90deg,#b88700,#f4c430,#b88700)}.tower-label{position:absolute;bottom:-32px;transform:translateX(-50%);color:var(--gold);font-weight:700;font-size:1.05rem}.disk{position:absolute;border-radius:999px;background:linear-gradient(180deg,#ffe08a,#f4c430 45%,#b88700);border:1px solid #8a6400;box-shadow:0 6px 14px rgba(0,0,0,.45),inset 0 2px 4px rgba(255,255,255,.35);transition:left .3s ease,bottom .3s ease;display:flex;align-items:center;justify-content:center;font-weight:700;color:#3a2600;font-size:.85rem}@media(max-width:768px){.hanoi-visualizer{padding:20px}.hanoi-visualizer h2{font-size:2rem}.stats{grid-template-columns:repeat(2,1fr)}.tower-label{font-size:.85rem}}
</style>
</head>
<body>
<main class="hanoi-visualizer">
<h2>Tower of Hanoi Visualizer</h2>
<div class="controls"><div class="disk-count-control"><span>Number of Disks:</span><button id="minus">-</button><input id="diskInput" readonly><button id="plus">+</button></div><button id="start">Start</button><button id="speed"></button><button id="reset">Reset</button></div>
<div class="stats"><div class="stat-box"><h4>Status</h4><p id="status"></p></div><div class="stat-box"><h4>Moves</h4><p id="moves"></p></div><div class="stat-box"><h4>Total Moves</h4><p id="total"></p></div><div class="stat-box"><h4>Disks</h4><p id="disks"></p></div></div>
<div class="towers-frame"><div id="towers" class="towers"></div></div>
</main>
<script>
const speedLevels=[["Very Slow",700],["Slow",450],["Normal",300],["Fast",150],["Very Fast",60]],MIN=2,MAX=8,PEG=[18,50,82],H=28,G=6,STEP=H+G,BASE=12;
let diskCount=5,pegs=[[],[],[]],moving=null,speedIndex=2,animating=false,status="Idle",moveCount=0,totalMoves=0;
const sleep=ms=>new Promise(r=>setTimeout(r,ms));function build(n){let p=[];for(let s=n;s>=1;s--)p.push(s);return[p,[],[]]}function diskWidth(s){return 54+((s-1)*(210-54))/(diskCount-1)}function rest(i){return BASE+i*STEP}function find(s){for(let p=0;p<3;p++){let i=pegs[p].indexOf(s);if(i!==-1)return{peg:p,index:i}}return{peg:0,index:0}}function style(s){let lift=BASE+diskCount*STEP+34,w=diskWidth(s),left,bottom;if(moving&&moving.size===s){let m=moving;left=PEG[m.phase==="lift"?m.from:m.to];bottom=m.phase==="drop"?rest(m.toIndex):BASE+diskCount*STEP+34}else{let spot=find(s);left=PEG[spot.peg];bottom=rest(spot.index)}return`left:calc(${left}% - ${w/2}px);bottom:${bottom}px;width:${w}px;height:${H}px`}
function render(){let height=BASE+diskCount*STEP+34+H+40;document.getElementById("diskInput").value=diskCount;document.getElementById("status").textContent=status;document.getElementById("moves").textContent=moveCount;document.getElementById("total").textContent=totalMoves;document.getElementById("disks").textContent=diskCount;document.getElementById("speed").textContent="Speed: "+speedLevels[speedIndex][0];["minus","plus","start"].forEach(id=>document.getElementById(id).disabled=animating);let html=`<div class="baseline"></div>`;PEG.forEach((l,i)=>html+=`<div class="pole" style="left:${l}%;height:${diskCount*STEP+30}px"></div><div class="tower-label" style="left:${l}%">Tower ${i+1}</div>`);for(let s=diskCount;s>=1;s--)html+=`<div class="disk" style="${style(s)}">${s}</div>`;let t=document.getElementById("towers");t.style.height=height+"px";t.innerHTML=html}
function reset(n=diskCount){if(animating)return;pegs=build(n);moving=null;status="Idle";moveCount=0;totalMoves=Math.pow(2,n)-1;render()}function change(d){if(animating)return;diskCount=Math.min(MAX,Math.max(MIN,diskCount+d));reset(diskCount)}function gen(n,from,to,aux,m){if(!n)return;gen(n-1,from,aux,to,m);m.push({disk:n,from,to});gen(n-1,aux,to,from,m)}
async function animate(disk,from,to,local){let toIndex=local[to].length;for(const phase of ["lift","across","drop"]){moving={size:disk,from,to,phase,toIndex};render();await sleep(speedLevels[speedIndex][1])}local[from].pop();local[to].push(disk);pegs=local.map(p=>[...p]);moving=null;render()}
async function solve(){if(animating)return;if(pegs[1].length||pegs[2].length)reset();animating=true;status="Solving...";render();await sleep(20);let moves=[];gen(diskCount,0,2,1,moves);totalMoves=moves.length;moveCount=0;let local=build(diskCount);for(const mv of moves){await animate(mv.disk,mv.from,mv.to,local);moveCount++;render()}status="Solved!";animating=false;render()}
minus.onclick=()=>change(-1);plus.onclick=()=>change(1);start.onclick=solve;speed.onclick=()=>{speedIndex=(speedIndex+1)%speedLevels.length;render()};document.getElementById("reset").onclick=()=>reset();reset();
</script>
</body>
</html>

About this Component

Tower of Hanoi is a classic recursion puzzle where disks must be moved from one rod to another while never placing a larger disk on top of a smaller one. This visualizer animates every recursive move between the source, auxiliary, and destination rods, helping learners connect the recursive calls to the visible disk movement. For n disks, Tower of Hanoi requires 2^n - 1 moves, which makes it a clear demonstration of exponential growth in recursive algorithms.

Explore More Components

Discover more components from the Playground.

Share Feedback