anycoder-d85efc6d / index.html
super7098PAZ's picture
Upload folder using huggingface_hub
dfd0157 verified
Raw
History Blame Contribute Delete
39.1 kB
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Python Loop Quiz - Visualizador Interactivo</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Fira+Code:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
mono: ['Fira Code', 'monospace'],
},
colors: {
glass: 'rgba(255, 255, 255, 0.05)',
glassBorder: 'rgba(255, 255, 255, 0.1)',
accent: '#06b6d4',
accentGlow: 'rgba(6, 182, 212, 0.3)',
correct: '#10b981',
incorrect: '#f43f5e',
},
animation: {
'gradient-x': 'gradient-x 15s ease infinite',
'float': 'float 6s ease-in-out infinite',
'pulse-slow': 'pulse 4s cubic-bezier(0.4, 0, 0.6, 1) infinite',
'slide-up': 'slideUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards',
'scale-in': 'scaleIn 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards',
'glow': 'glow 2s ease-in-out infinite alternate',
},
keyframes: {
'gradient-x': {
'0%, 100%': {
'background-size': '200% 200%',
'background-position': 'left center'
},
'50%': {
'background-size': '200% 200%',
'background-position': 'right center'
},
},
float: {
'0%, 100%': { transform: 'translateY(0)' },
'50%': { transform: 'translateY(-20px)' },
},
slideUp: {
'0%': { transform: 'translateY(30px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
},
scaleIn: {
'0%': { transform: 'scale(0.9)', opacity: '0' },
'100%': { transform: 'scale(1)', opacity: '1' },
},
glow: {
'0%': { boxShadow: '0 0 20px rgba(6, 182, 212, 0.2)' },
'100%': { boxShadow: '0 0 40px rgba(6, 182, 212, 0.5)' },
}
}
}
}
}
</script>
<style>
body {
background: linear-gradient(135deg, #0f172a 0%, #1e1b4b 50%, #0f172a 100%);
background-size: 400% 400%;
animation: gradientMove 15s ease infinite;
}
@keyframes gradientMove {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.glass-panel {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
}
.code-line {
counter-increment: line;
position: relative;
padding-left: 3rem;
}
.code-line::before {
content: counter(line);
position: absolute;
left: 0;
top: 0;
width: 2.5rem;
text-align: right;
color: rgba(255, 255, 255, 0.3);
font-size: 0.875rem;
user-select: none;
}
.option-card {
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
.option-card::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);
transition: left 0.5s;
}
.option-card:hover::before {
left: 100%;
}
.option-card:hover {
transform: translateY(-4px) scale(1.02);
border-color: rgba(6, 182, 212, 0.4);
box-shadow: 0 20px 40px -10px rgba(6, 182, 212, 0.2);
}
.option-card.selected-correct {
background: rgba(16, 185, 129, 0.1);
border-color: #10b981;
box-shadow: 0 0 30px rgba(16, 185, 129, 0.2);
}
.option-card.selected-incorrect {
background: rgba(244, 63, 94, 0.1);
border-color: #f43f5e;
box-shadow: 0 0 30px rgba(244, 63, 94, 0.2);
animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both;
}
@keyframes shake {
10%, 90% { transform: translate3d(-1px, 0, 0); }
20%, 80% { transform: translate3d(2px, 0, 0); }
30%, 50%, 70% { transform: translate3d(-4px, 0, 0); }
40%, 60% { transform: translate3d(4px, 0, 0); }
}
.iteration-node {
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
opacity: 0;
transform: translateY(20px) scale(0.9);
}
.iteration-node.active {
opacity: 1;
transform: translateY(0) scale(1);
}
.iteration-node::after {
content: '';
position: absolute;
bottom: -2rem;
left: 50%;
width: 2px;
height: 2rem;
background: linear-gradient(to bottom, rgba(6, 182, 212, 0.5), transparent);
transform: translateX(-50%);
}
.iteration-node:last-child::after {
display: none;
}
.highlight-text {
background: linear-gradient(120deg, rgba(6, 182, 212, 0.2) 0%, rgba(6, 182, 212, 0.2) 100%);
background-repeat: no-repeat;
background-size: 100% 40%;
background-position: 0 90%;
transition: background-size 0.3s ease;
}
.highlight-text:hover {
background-size: 100% 100%;
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.02);
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.15);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.25);
}
.confetti {
position: absolute;
width: 10px;
height: 10px;
background-color: #f0f;
animation: fall linear forwards;
}
@keyframes fall {
to {
transform: translateY(100vh) rotate(720deg);
opacity: 0;
}
}
.syntax-keyword { color: #c678dd; }
.syntax-var { color: #e06c75; }
.syntax-number { color: #d19a66; }
.syntax-func { color: #61afef; }
.syntax-operator { color: #56b6c2; }
</style>
</head>
<body class="min-h-screen text-slate-200 font-sans overflow-x-hidden selection:bg-cyan-500 selection:text-white">
<!-- Background Elements -->
<div class="fixed inset-0 pointer-events-none overflow-hidden">
<div class="absolute -top-40 -left-40 w-96 h-96 bg-cyan-500/10 rounded-full blur-3xl animate-float"></div>
<div class="absolute top-1/2 -right-40 w-96 h-96 bg-purple-500/10 rounded-full blur-3xl animate-float" style="animation-delay: 2s;"></div>
<div class="absolute -bottom-40 left-1/3 w-96 h-96 bg-emerald-500/10 rounded-full blur-3xl animate-float" style="animation-delay: 4s;"></div>
</div>
<!-- Header -->
<header class="relative z-10 w-full px-6 py-6 flex flex-col sm:flex-row items-center justify-between gap-4 border-b border-white/5 bg-black/20 backdrop-blur-sm">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-gradient-to-br from-cyan-400 to-blue-600 flex items-center justify-center shadow-lg shadow-cyan-500/20">
<i class="fa-brands fa-python text-white text-xl"></i>
</div>
<div>
<h1 class="text-xl font-bold tracking-tight text-white">Python Loop Master</h1>
<p class="text-xs text-slate-400">Visualizador de Bucles Interactivo</p>
</div>
</div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="group flex items-center gap-2 px-4 py-2 rounded-full bg-white/5 border border-white/10 hover:bg-white/10 hover:border-cyan-500/30 transition-all duration-300 text-sm font-medium text-slate-300 hover:text-cyan-400">
<i class="fa-solid fa-code text-xs group-hover:rotate-12 transition-transform"></i>
<span>Built with anycoder</span>
<i class="fa-solid fa-arrow-up-right-from-square text-xs opacity-50 group-hover:opacity-100"></i>
</a>
</header>
<main class="relative z-10 container mx-auto px-4 py-8 max-w-6xl">
<!-- Question Section -->
<div class="grid lg:grid-cols-2 gap-8 mb-12">
<!-- Code Panel -->
<div class="glass-panel rounded-3xl p-1 animate-slide-up" style="animation-delay: 0.1s;">
<div class="bg-black/40 rounded-[1.3rem] p-6 sm:p-8 h-full relative overflow-hidden group">
<!-- Decorative top bar -->
<div class="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-cyan-500 via-purple-500 to-cyan-500 opacity-50"></div>
<div class="flex items-center justify-between mb-6">
<div class="flex items-center gap-2">
<div class="w-3 h-3 rounded-full bg-red-500/80"></div>
<div class="w-3 h-3 rounded-full bg-yellow-500/80"></div>
<div class="w-3 h-3 rounded-full bg-green-500/80"></div>
</div>
<span class="text-xs font-mono text-slate-500 uppercase tracking-wider">loop_example.py</span>
</div>
<div class="font-mono text-sm sm:text-base leading-relaxed overflow-x-auto">
<div class="code-line"><span class="syntax-var">i</span><span class="syntax-operator">=</span><span class="syntax-number">100</span></div>
<div class="code-line"><span class="syntax-keyword">while</span>(<span class="syntax-var">i</span><span class="syntax-operator"><=</span><span class="syntax-number">200</span>):</div>
<div class="code-line pl-12 sm:pl-16"><span class="syntax-func">print</span>(<span class="syntax-var">i</span>)</div>
<div class="code-line pl-12 sm:pl-16"><span class="syntax-var">i</span><span class="syntax-operator">+=</span><span class="syntax-number">20</span></div>
</div>
<div class="mt-6 pt-6 border-t border-white/5 flex items-center gap-3 text-slate-400 text-sm">
<i class="fa-solid fa-circle-info text-cyan-500"></i>
<span>Analiza el bucle cuidadosamente antes de responder</span>
</div>
</div>
</div>
<!-- Question & Options -->
<div class="flex flex-col gap-6 animate-slide-up" style="animation-delay: 0.2s;">
<div class="glass-panel rounded-3xl p-6 sm:p-8">
<div class="flex items-start gap-4 mb-6">
<span class="flex-shrink-0 w-10 h-10 rounded-xl bg-cyan-500/10 border border-cyan-500/20 flex items-center justify-center text-cyan-400 font-bold text-lg">?</span>
<h2 class="text-xl sm:text-2xl font-semibold text-white leading-snug">
¿Cuántas veces se ejecutará el siguiente bucle en Python?
</h2>
</div>
<div class="grid gap-4" id="options-container">
<button onclick="selectOption('A', true)" class="option-card glass-panel rounded-2xl p-5 text-left group border border-white/10" data-option="A">
<div class="flex items-center gap-4">
<span class="flex-shrink-0 w-12 h-12 rounded-xl bg-white/5 border border-white/10 group-hover:border-cyan-500/30 group-hover:bg-cyan-500/10 transition-all flex items-center justify-center font-bold text-lg text-slate-300 group-hover:text-cyan-400">A</span>
<div>
<span class="text-2xl font-bold text-white block">6</span>
<span class="text-sm text-slate-400">El bucle itera seis veces</span>
</div>
<div class="ml-auto opacity-0 group-hover:opacity-100 transition-opacity">
<i class="fa-solid fa-chevron-right text-cyan-400"></i>
</div>
</div>
</button>
<button onclick="selectOption('B', false)" class="option-card glass-panel rounded-2xl p-5 text-left group border border-white/10" data-option="B">
<div class="flex items-center gap-4">
<span class="flex-shrink-0 w-12 h-12 rounded-xl bg-white/5 border border-white/10 group-hover:border-cyan-500/30 group-hover:bg-cyan-500/10 transition-all flex items-center justify-center font-bold text-lg text-slate-300 group-hover:text-cyan-400">B</span>
<div>
<span class="text-2xl font-bold text-white block">100</span>
<span class="text-sm text-slate-400">Iteraciones igual al valor inicial</span>
</div>
<div class="ml-auto opacity-0 group-hover:opacity-100 transition-opacity">
<i class="fa-solid fa-chevron-right text-cyan-400"></i>
</div>
</div>
</button>
<button onclick="selectOption('C', false)" class="option-card glass-panel rounded-2xl p-5 text-left group border border-white/10" data-option="C">
<div class="flex items-center gap-4">
<span class="flex-shrink-0 w-12 h-12 rounded-xl bg-white/5 border border-white/10 group-hover:border-cyan-500/30 group-hover:bg-cyan-500/10 transition-all flex items-center justify-center font-bold text-lg text-slate-300 group-hover:text-cyan-400">C</span>
<div>
<span class="text-2xl font-bold text-white block">200</span>
<span class="text-sm text-slate-400">Iteraciones igual al valor límite</span>
</div>
<div class="ml-auto opacity-0 group-hover:opacity-100 transition-opacity">
<i class="fa-solid fa-chevron-right text-cyan-400"></i>
</div>
</div>
</button>
</div>
</div>
</div>
</div>
<!-- Answer Feedback (Hidden initially) -->
<div id="feedback-section" class="hidden mb-12 animate-slide-up">
<div class="glass-panel rounded-3xl p-1 border-2 border-emerald-500/20">
<div class="bg-emerald-500/5 rounded-[1.3rem] p-6 sm:p-8 relative overflow-hidden">
<div class="absolute top-0 right-0 w-64 h-64 bg-emerald-500/10 rounded-full blur-3xl -translate-y-1/2 translate-x-1/2"></div>
<div class="relative z-10 flex flex-col sm:flex-row items-start sm:items-center gap-4 mb-6">
<div class="w-14 h-14 rounded-2xl bg-emerald-500/20 border border-emerald-500/30 flex items-center justify-center animate-scale-in">
<i class="fa-solid fa-check text-2xl text-emerald-400"></i>
</div>
<div>
<h3 class="text-2xl font-bold text-white mb-1">¡Correcto! La respuesta es <span class="text-emerald-400">A) 6</span></h3>
<p class="text-slate-400">Has demostrado un excelente dominio de los bucles <code class="bg-white/10 px-2 py-0.5 rounded text-emerald-300 font-mono text-sm">while</code> en Python.</p>
</div>
</div>
<!-- Detailed Explanation -->
<div class="space-y-6 relative z-10">
<div class="bg-black/20 rounded-2xl p-6 border border-white/5">
<h4 class="text-lg font-semibold text-white mb-4 flex items-center gap-2">
<i class="fa-solid fa-list-ol text-cyan-400"></i>
Explicación Detallada
</h4>
<div class="space-y-4 text-slate-300 leading-relaxed">
<p>
Para determinar cuántas veces se ejecuta el bucle, debemos analizar paso a paso la evolución de la variable <span class="font-mono text-cyan-300 bg-cyan-500/10 px-1.5 py-0.5 rounded">i</span>:
</p>
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead>
<tr class="border-b border-white/10">
<th class="pb-3 pr-4 text-slate-400 font-medium text-sm uppercase tracking-wider">Iteración</th>
<th class="pb-3 pr-4 text-slate-400 font-medium text-sm uppercase tracking-wider">Valor inicial de i</th>
<th class="pb-3 pr-4 text-slate-400 font-medium text-sm uppercase tracking-wider">Condición (i <= 200)</th>
<th class="pb-3 pr-4 text-slate-400 font-medium text-sm uppercase tracking-wider">Output</th>
<th class="pb-3 text-slate-400 font-medium text-sm uppercase tracking-wider">Nuevo valor de i</th>
</tr>
</thead>
<tbody class="font-mono text-sm">
<tr class="border-b border-white/5 hover:bg-white/5 transition-colors">
<td class="py-3 pr-4 text-emerald-400 font-bold">1</td>
<td class="py-3 pr-4 text-white">100</td>
<td class="py-3 pr-4 text-emerald-400">True <span class="text-xs opacity-50"></span></td>
<td class="py-3 pr-4 text-cyan-300">100</td>
<td class="py-3 text-white">120</td>
</tr>
<tr class="border-b border-white/5 hover:bg-white/5 transition-colors">
<td class="py-3 pr-4 text-emerald-400 font-bold">2</td>
<td class="py-3 pr-4 text-white">120</td>
<td class="py-3 pr-4 text-emerald-400">True <span class="text-xs opacity-50"></span></td>
<td class="py-3 pr-4 text-cyan-300">120</td>
<td class="py-3 text-white">140</td>
</tr>
<tr class="border-b border-white/5 hover:bg-white/5 transition-colors">
<td class="py-3 pr-4 text-emerald-400 font-bold">3</td>
<td class="py-3 pr-4 text-white">140</td>
<td class="py-3 pr-4 text-emerald-400">True <span class="text-xs opacity-50"></span></td>
<td class="py-3 pr-4 text-cyan-300">140</td>
<td class="py-3 text-white">160</td>
</tr>
<tr class="border-b border-white/5 hover:bg-white/5 transition-colors">
<td class="py-3 pr-4 text-emerald-400 font-bold">4</td>
<td class="py-3 pr-4 text-white">160</td>
<td class="py-3 pr-4 text-emerald-400">True <span class="text-xs opacity-50"></span></td>
<td class="py-3 pr-4 text-cyan-300">160</td>
<td class="py-3 text-white">180</td>
</tr>
<tr class="border-b border-white/5 hover:bg-white/5 transition-colors">
<td class="py-3 pr-4 text-emerald-400 font-bold">5</td>
<td class="py-3 pr-4 text-white">180</td>
<td class="py-3 pr-4 text-emerald-400">True <span class="text-xs opacity-50"></span></td>
<td class="py-3 pr-4 text-cyan-300">180</td>
<td class="py-3 text-white">200</td>
</tr>
<tr class="border-b border-white/5 hover:bg-white/5 transition-colors bg-emerald-500/5">
<td class="py-3 pr-4 text-emerald-400 font-bold">6</td>
<td class="py-3 pr-4 text-white">200</td>
<td class="py-3 pr-4 text-emerald-400">True <span class="text-xs opacity-50"></span></td>
<td class="py-3 pr-4 text-cyan-300">200</td>
<td class="py-3 text-white">220</td>
</tr>
<tr class="hover:bg-white/5 transition-colors opacity-60">
<td class="py-3 pr-4 text-rose-400 font-bold"></td>
<td class="py-3 pr-4 text-white">220</td>
<td class="py-3 pr-4 text-rose-400">False <span class="text-xs opacity-50"></span></td>
<td class="py-3 pr-4 text-slate-500"></td>
<td class="py-3 text-slate-500">Fin</td>
</tr>
</tbody>
</table>
</div>
<div class="bg-cyan-500/5 border border-cyan-500/20 rounded-xl p-4 flex items-start gap-3 mt-4">
<i class="fa-solid fa-lightbulb text-cyan-400 mt-1"></i>
<div>
<p class="text-cyan-100 font-medium mb-1">Punto clave</p>
<p class="text-sm text-cyan-200/70">
La condición se evalúa como <span class="font-mono text-cyan-300">True</span> cuando <span class="font-mono text-cyan-300">i=200</span> porque el operador es <span class="font-mono text-cyan-300"><=</span> (menor o igual). Por eso se incluye el valor 200. Después de esa iteración, <span class="font-mono text-cyan-300">i</span> pasa a valer 220 y el bucle termina.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Interactive Visualizer -->
<div class="glass-panel rounded-3xl p-6 sm:p-8 mb-12 animate-slide-up" style="animation-delay: 0.3s;">
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 mb-8">
<div>
<h3 class="text-xl font-bold text-white flex items-center gap-2">
<i class="fa-solid fa-microchip text-cyan-400"></i>
Visualizador de Ejecución
</h3>
<p class="text-sm text-slate-400 mt-1">Observa cómo cambia el valor de <span class="font-mono text-cyan-300">i</span> en cada iteración</p>
</div>
<button onclick="runSimulation()" id="sim-btn" class="px-6 py-3 rounded-xl bg-cyan-500 hover:bg-cyan-400 text-slate-900 font-bold text-sm transition-all hover:shadow-lg hover:shadow-cyan-500/25 active:scale-95 flex items-center gap-2">
<i class="fa-solid fa-play"></i>
Ejecutar Simulación
</button>
</div>
<div class="relative">
<!-- Progress Bar -->
<div class="absolute top-8 left-0 right-0 h-1 bg-white/5 rounded-full overflow-hidden">
<div id="progress-bar" class="h-full bg-gradient-to-r from-cyan-500 to-emerald-400 w-0 transition-all duration-700 ease-out"></div>
</div>
<!-- Iteration Nodes -->
<div class="grid grid-cols-3 sm:grid-cols-6 gap-4 relative pt-12 pb-4" id="visualizer-container">
<!-- Generated by JS -->
</div>
<!-- Console Output -->
<div class="mt-6 bg-black/40 rounded-2xl p-4 border border-white/5 font-mono text-sm">
<div class="flex items-center gap-2 mb-3 text-slate-500 text-xs uppercase tracking-wider font-sans">
<i class="fa-solid fa-terminal"></i>
Consola de Salida
</div>
<div id="console-output" class="h-8 flex items-center gap-2 text-slate-300 overflow-x-auto whitespace-nowrap">
<span class="text-slate-600 italic">Esperando ejecución...</span>
</div>
</div>
</div>
</div>
<!-- Tips Section -->
<div class="grid sm:grid-cols-3 gap-4 animate-slide-up" style="animation-delay: 0.4s;">
<div class="glass-panel rounded-2xl p-5 hover:bg-white/5 transition-colors group">
<div class="w-10 h-10 rounded-lg bg-purple-500/10 border border-purple-500/20 flex items-center justify-center mb-3 group-hover:scale-110 transition-transform">
<i class="fa-solid fa-plus-minus text-purple-400"></i>
</div>
<h4 class="font-semibold text-white mb-1">Incremento Constante</h4>
<p class="text-sm text-slate-400">El valor aumenta 20 unidades por iteración. Siempre verifica el paso (<span class="font-mono text-xs">i += n</span>).</p>
</div>
<div class="glass-panel rounded-2xl p-5 hover:bg-white/5 transition-colors group">
<div class="w-10 h-10 rounded-lg bg-amber-500/10 border border-amber-500/20 flex items-center justify-center mb-3 group-hover:scale-110 transition-transform">
<i class="fa-solid fa-less-than-equal text-amber-400"></i>
</div>
<h4 class="font-semibold text-white mb-1">Condición Inclusiva</h4>
<p class="text-sm text-slate-400">El operador <span class="font-mono text-xs"><=</span> incluye el límite (200), generando una iteración extra comparado con <span class="font-mono text-xs"><</span>.</p>
</div>
<div class="glass-panel rounded-2xl p-5 hover:bg-white/5 transition-colors group">
<div class="w-10 h-10 rounded-lg bg-rose-500/10 border border-rose-500/20 flex items-center justify-center mb-3 group-hover:scale-110 transition-transform">
<i class="fa-solid fa-calculator text-rose-400"></i>
</div>
<h4 class="font-semibold text-white mb-1">Cálculo Formal</h4>
<p class="text-sm text-slate-400">Fórmula: <span class="font-mono text-xs">((200-100)/20)+1 = 6</span>. Útil para bucles con muchas iteraciones.</p>
</div>
</div>
</main>
<!-- Footer -->
<footer class="relative z-10 border-t border-white/5 mt-12 py-8 text-center text-slate-500 text-sm">
<p>Python Loop Master • Aprende interactivamente</p>
</footer>
<script>
let hasAnswered = false;
let simulationRunning = false;
// Initialize visualizer nodes
const iterations = [
{ i: 100, out: 100, next: 120 },
{ i: 120, out: 120, next: 140 },
{ i: 140, out: 140, next: 160 },
{ i: 160, out: 160, next: 180 },
{ i: 180, out: 180, next: 200 },
{ i: 200, out: 200, next: 220 }
];
function initVisualizer() {
const container = document.getElementById('visualizer-container');
container.innerHTML = '';
iterations.forEach((iter, idx) => {
const node = document.createElement('div');
node.className = 'iteration-node flex flex-col items-center relative';
node.id = `node-${idx}`;
node.innerHTML = `
<div class="w-16 h-16 sm:w-20 sm:h-20 rounded-2xl bg-white/5 border-2 border-white/10 flex flex-col items-center justify-center relative z-10 transition-all duration-500" id="node-box-${idx}">
<span class="text-xs text-slate-500 mb-0.5">i =</span>
<span class="text-xl sm:text-2xl font-bold text-white font-mono">${iter.i}</span>
</div>
<div class="mt-4 text-center opacity-0 transition-all duration-500 transform translate-y-2" id="node-info-${idx}">
<div class="text-xs text-emerald-400 font-mono mb-0.5">print(${iter.out})</div>
<div class="text-[10px] text-slate-500">i → ${iter.next}</div>
</div>
`;
container.appendChild(node);
});
}
initVisualizer();
function selectOption(option, isCorrect) {
if (hasAnswered) return;
hasAnswered = true;
const buttons = document.querySelectorAll('.option-card');
buttons.forEach(btn => {
btn.disabled = true;
btn.style.cursor = 'default';
const btnOption = btn.dataset.option;
if (btnOption === option) {
btn.classList.add(isCorrect ? 'selected-correct' : 'selected-incorrect');
} else if (btnOption === 'A' && !isCorrect) {
// Highlight correct answer if wrong was selected
setTimeout(() => {
btn.classList.add('selected-correct');
}, 500);
}
if (!isCorrect && btnOption !== option && btnOption !== 'A') {
btn.style.opacity = '0.5';
}
});
if (isCorrect) {
createConfetti();
document.getElementById('feedback-section').classList.remove('hidden');
setTimeout(() => {
document.getElementById('feedback-section').scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}, 300);
} else {
// Show feedback anyway after a delay
setTimeout(() => {
document.getElementById('feedback-section').classList.remove('hidden');
document.getElementById('feedback-section').scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}, 1000);
}
}
async function runSimulation() {
if (simulationRunning) return;
simulationRunning = true;
const btn = document.getElementById('sim-btn');
const originalBtnText = btn.innerHTML;
btn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Ejecutando...';
btn.classList.add('opacity-75');
const consoleOutput = document.getElementById('console-output');
const progressBar = document.getElementById('progress-bar');
// Reset
consoleOutput.innerHTML = '';
progressBar.style.width = '0%';
iterations.forEach((_, idx) => {
document.getElementById(`node-box-${idx}`).className = 'w-16 h-16 sm:w-20 sm:h-20 rounded-2xl bg-white/5 border-2 border-white/10 flex flex-col items-center justify-center relative z-10 transition-all duration-500';
document.getElementById(`node-info-${idx}`).classList.remove('opacity-100', 'translate-y-0');
document.getElementById(`node-info-${idx}`).classList.add('opacity-0', 'translate-y-2');
});
await wait(500);
for (let idx = 0; idx < iterations.length; idx++) {
const iter = iterations[idx];
// Highlight node
const box = document.getElementById(`node-box-${idx}`);
box.classList.remove('border-white/10', 'bg-white/5');
box.classList.add('border-cyan-400', 'bg-cyan-500/20', 'shadow-lg', 'shadow-cyan-500/20');
// Show info
const info = document.getElementById(`node-info-${idx}`);
info.classList.remove('opacity-0', 'translate-y-2');
info.classList.add('opacity-100', 'translate-y-0');
// Update console
const outputSpan = document.createElement('span');
outputSpan.className = 'inline-flex items-center gap-2 animate-scale-in';
outputSpan.innerHTML = `<span class="text-slate-500 text-xs">${idx + 1}.</span><span class="text-cyan-300">${iter.out}</span>`;
consoleOutput.appendChild(outputSpan);
// Update progress
progressBar.style.width = `${((idx + 1) / iterations.length) * 100}%`;
await wait(800);
// Mark as completed
box.classList.remove('border-cyan-400', 'bg-cyan-500/20');
box.classList.add('border-emerald-500/50', 'bg-emerald-500/10');
}
// Final state
const finalSpan = document.createElement('span');
finalSpan.className = 'text-emerald-400 text-xs ml-2 border-l border-white/10 pl-2 animate-scale-in';
finalSpan.textContent = '✓ Bucle completado (6 iteraciones)';
consoleOutput.appendChild(finalSpan);
btn.innerHTML = originalBtnText;
btn.classList.remove('opacity-75');
simulationRunning = false;
}
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function createConfetti() {
const colors = ['#06b6d4', '#10b981', '#f43f5e', '#f59e0b', '#8b5cf6'];
for (let i = 0; i < 50; i++) {
setTimeout(() => {
const confetti = document.createElement('div');
confetti.className = 'confetti';
confetti.style.left = Math.random() * 100 + 'vw';
confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
confetti.style.animationDuration = (Math.random() * 3 + 2) + 's';
confetti.style.opacity = Math.random();
confetti.style.borderRadius = Math.random() > 0.5 ? '50%' : '0';
document.body.appendChild(confetti);
setTimeout(() => confetti.remove(), 5000);
}, i * 30);
}
}
// Entrance animations for iteration nodes on scroll
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const nodes = entry.target.querySelectorAll('.iteration-node');
nodes.forEach((node, idx) => {
setTimeout(() => {
node.classList.add('active');
}, idx * 100);
});
}
});
}, { threshold: 0.2 });
document.add