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
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.



