jueves, 16 de julio de 2026

✦ Tutorial del Código del Juego ✦

📸 Vista previa Juego de puzzle 3x3
Vista previa del juego de puzzle

👋 Holis, tuve un comentario donde me pedían tuto del jueguito de las imágenes.

📌 Bueno, no es tan complicado, pero a la hora de editarlo les recomiendo tener Sublime Text o bloc de notas.

🎨 Personalización de colores

Como verán, hay varias cosas en negritas que son los colores del gadget. Aquí hay dos tipos: # y rgba(), que son dos formas de poner color. Yo usé las dos, pero para que no tengan que inventarse colores como yo al principio, les dejaré las paletas de colores que usé:

💡 El primero es de rgba y el segundo #. Ahí pueden personalizar los colores como gusten.

🖼️ LAS IMÁGENES

En este caso usarán el vínculo de la imagen, yo las tomo de Pinterest, pueden elegir la que sea ya que se ajustará automáticamente. Es muy importante que dejen las comillas.

const IMAGES = [
  'https://i.pinimg.com/1200x/2f/b9/2f/2fb92f6a4043bea724ee60b8c90fa946.jpg',
  'https://i.pinimg.com/1200x/2f/b9/2f/2fb92f6a4043bea724ee60b8c90fa946.jpg',
  'https://i.pinimg.com/1200x/2f/b9/2f/2fb92f6a4043bea724ee60b8c90fa946.jpg'
];

🔘 LOS BOTONES

Pueden cambiar el texto pero la función se mantendrá igual y también pueden cambiar los emojis por los que ustedes gusten. En caso de que su herramienta no tenga teclado de emojis, les recomiendo este link:

💻 CÓDIGO COMPLETO DEL JUEGO

Aquí tienen el código completo para copiar y pegar en su blog:

<style>
  #puzzle-wrapper {
    max-width: 100%;
    width: 100%;
    margin: 0;
    padding: 15px 10px;
    font-family: 'Segoe UI', Arial, sans-serif;
    text-align: center;
    background: linear-gradient(145deg, #2d1b3d, #1f112b);
    border-radius: 16px;
    box-shadow: 0 4px 20px rgba(106, 13, 173, 0.5);
    border: 1px solid rgba(155, 77, 255, 0.2);
    box-sizing: border-box;
    overflow: hidden;
  }

  #puzzle-container {
    width: 100%;
    max-width: 280px;
    aspect-ratio: 1 / 1;
    margin: 0 auto 12px auto;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: repeat(3, 1fr);
    gap: 3px;
    padding: 3px;
    background-color: #1a0f24;
    border-radius: 12px;
    box-shadow: 0 4px 20px rgba(106, 13, 173, 0.5), inset 0 0 30px rgba(155, 77, 255, 0.1);
    box-sizing: border-box;
  }

  .puzzle-piece {
    width: 100%;
    height: 100%;
    background-size: 300% 300%;
    cursor: pointer;
    border-radius: 4px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    box-sizing: border-box;
    transition: transform 0.1s ease, opacity 0.2s, box-shadow 0.2s;
    min-width: 0;
    min-height: 0;
  }

  .puzzle-piece:not(.empty):hover {
    transform: scale(0.92);
    opacity: 0.85;
    box-shadow: 0 0 15px rgba(155, 77, 255, 0.3);
  }

  .puzzle-piece.empty {
    background-image: none !important;
    background-color: #120a1a !important;
    border: 1px dashed #5a3a6a;
    cursor: default;
  }

  .glitter-btn {
    width: 64px;
    height: 64px;
    border: none;
    border-radius: 12px;
    margin: 4px 5px;
    font-size: 26px;
    font-weight: bold;
    cursor: pointer;
    color: white;
    text-shadow: 0 0 5px rgba(255, 255, 255, 0.5);
    background: linear-gradient(135deg, #7b2fbe, #9b4dff, #7b2fbe);
    background-size: 300% 300%;
    box-shadow: 0 0 20px rgba(155, 77, 255, 0.5), inset 0 0 15px rgba(255, 255, 255, 0.15);
    transition: all 0.25s ease;
    position: relative;
    overflow: hidden;
    flex-shrink: 0;
  }

  .glitter-btn::before {
    content: '';
    position: absolute;
    top: -50%;
    left: -50%;
    width: 200%;
    height: 200%;
    background: radial-gradient(circle at 30% 40%, rgba(255, 255, 255, 0.3) 0%, transparent 60%),
                radial-gradient(circle at 70% 80%, rgba(255, 215, 0, 0.25) 0%, transparent 50%),
                radial-gradient(circle at 10% 90%, rgba(255, 255, 255, 0.2) 0%, transparent 40%),
                radial-gradient(circle at 90% 10%, rgba(200, 150, 255, 0.3) 0%, transparent 50%);
    background-size: 200% 200%;
    animation: glitterMove 3s linear infinite;
    pointer-events: none;
  }

  .glitter-btn::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-image: 
      radial-gradient(2px 2px at 20% 30%, rgba(255, 255, 255, 0.8), transparent),
      radial-gradient(2px 2px at 40% 70%, rgba(255, 255, 255, 0.6), transparent),
      radial-gradient(3px 3px at 60% 20%, rgba(255, 215, 0, 0.7), transparent),
      radial-gradient(2px 2px at 80% 50%, rgba(255, 255, 255, 0.9), transparent),
      radial-gradient(2px 2px at 10% 80%, rgba(200, 150, 255, 0.7), transparent),
      radial-gradient(3px 3px at 70% 90%, rgba(255, 255, 255, 0.5), transparent),
      radial-gradient(2px 2px at 90% 30%, rgba(255, 215, 0, 0.6), transparent);
    background-size: 150% 150%;
    animation: sparkle 4s ease-in-out infinite alternate;
    pointer-events: none;
  }

  @keyframes glitterMove {
    0% { background-position: 0% 0%; }
    50% { background-position: 100% 100%; }
    100% { background-position: 0% 0%; }
  }

  @keyframes sparkle {
    0% { opacity: 0.3; transform: scale(1); }
    100% { opacity: 1; transform: scale(1.1); }
  }

  .glitter-btn:hover {
    transform: scale(1.08) rotate(-2deg);
    box-shadow: 0 0 40px rgba(155, 77, 255, 0.9), inset 0 0 25px rgba(255, 255, 255, 0.25);
  }

  .glitter-btn:active {
    transform: scale(0.92);
  }

  #btn-group {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 8px;
    margin: 6px 0 8px 0;
    flex-wrap: wrap;
  }

  #image-counter {
    font-size: 13px;
    color: #a07bb5;
    background: rgba(26, 15, 36, 0.6);
    padding: 4px 12px;
    border-radius: 20px;
    border: 1px solid rgba(155, 77, 255, 0.15);
    display: inline-block;
    margin-top: 2px;
  }

  #message {
    font-size: 15px;
    font-weight: bold;
    min-height: 26px;
    color: #c084fc;
    text-shadow: 0 0 20px rgba(155, 77, 255, 0.5), 0 0 40px rgba(155, 77, 255, 0.2);
    margin: 4px 0 2px 0;
    padding: 6px 8px;
    background: rgba(26, 15, 36, 0.5);
    border-radius: 10px;
    border: 1px solid rgba(155, 77, 255, 0.1);
    word-wrap: break-word;
    box-sizing: border-box;
  }

  @media (max-width: 350px) {
    #puzzle-container {
      max-width: 220px;
      gap: 2px;
      padding: 2px;
    }
    .glitter-btn {
      width: 54px;
      height: 54px;
      font-size: 20px;
    }
    #puzzle-wrapper {
      padding: 10px 6px;
    }
  }

  @media (min-width: 351px) and (max-width: 450px) {
    #puzzle-container {
      max-width: 250px;
    }
    .glitter-btn {
      width: 60px;
      height: 60px;
      font-size: 24px;
    }
  }
</style>

<div id="puzzle-wrapper">
  <div id="puzzle-container"></div>
  <div id="btn-group">
    <button class="glitter-btn" onclick="shufflePuzzle()" title="Mezclar">🔀</button>
    <button class="glitter-btn" onclick="nextImage()" title="Cambiar imagen">🖼️</button>
    <button class="glitter-btn" onclick="resetPuzzle()" title="Reiniciar">🔄</button>
  </div>
  <div id="image-counter">Imagen <span id="current-img-num">1</span> de <span id="total-img-num">3</span></div>
  <div id="message"></div>
</div>

<script>
  const IMAGES = [
    'https://i.pinimg.com/1200x/2f/b9/2f/2fb92f6a4043bea724ee60b8c90fa946.jpg',
    'https://i.pinimg.com/1200x/2f/b9/2f/2fb92f6a4043bea724ee60b8c90fa946.jpg',
    'https://i.pinimg.com/1200x/2f/b9/2f/2fb92f6a4043bea724ee60b8c90fa946.jpg'
  ];

  const GRID_SIZE = 3;
  const TOTAL_PIECES = GRID_SIZE * GRID_SIZE;

  let pieces = [];
  let emptyIndex = TOTAL_PIECES - 1;
  let moves = 0;
  let gameStarted = false;
  let currentImageIndex = 0;
  let currentImageUrl = IMAGES[0];

  function initPuzzle() {
    const container = document.getElementById('puzzle-container');
    container.innerHTML = '';
    pieces = [];
    for (let i = 0; i < TOTAL_PIECES; i++) {
      pieces.push(i);
    }
    emptyIndex = TOTAL_PIECES - 1;
    moves = 0;
    gameStarted = false;
    document.getElementById('message').textContent = '';
    renderPuzzle();
  }

  function renderPuzzle() {
    const container = document.getElementById('puzzle-container');
    container.innerHTML = '';
    for (let i = 0; i < pieces.length; i++) {
      const piece = document.createElement('div');
      piece.className = 'puzzle-piece';
      if (pieces[i] === -1) {
        piece.classList.add('empty');
      } else {
        const row = Math.floor(pieces[i] / GRID_SIZE);
        const col = pieces[i] % GRID_SIZE;
        piece.style.backgroundImage = `url('${currentImageUrl}')`;
        piece.style.backgroundPosition = `-${col * 100}% -${row * 100}%`;
        piece.dataset.index = i;
        piece.addEventListener('click', () => movePiece(i));
      }
      container.appendChild(piece);
    }
    document.getElementById('current-img-num').textContent = currentImageIndex + 1;
    document.getElementById('total-img-num').textContent = IMAGES.length;
  }

  function movePiece(index) {
    if (!gameStarted) gameStarted = true;
    const emptyRow = Math.floor(emptyIndex / GRID_SIZE);
    const emptyCol = emptyIndex % GRID_SIZE;
    const pieceRow = Math.floor(index / GRID_SIZE);
    const pieceCol = index % GRID_SIZE;

    if ((Math.abs(emptyRow - pieceRow) === 1 && emptyCol === pieceCol) ||
        (Math.abs(emptyCol - pieceCol) === 1 && emptyRow === pieceRow)) {
      pieces[emptyIndex] = pieces[index];
      pieces[index] = -1;
      emptyIndex = index;
      moves++;
      renderPuzzle();
      checkWin();
    }
  }

  function nextImage() {
    currentImageIndex = (currentImageIndex + 1) % IMAGES.length;
    currentImageUrl = IMAGES[currentImageIndex];
    initPuzzle();
    shufflePuzzle();
    moves = 0;
    gameStarted = false;
    document.getElementById('message').textContent = '🖼️ Imagen cambiada';
  }

  function shufflePuzzle() {
    for (let i = 0; i < 200; i++) {
      const emptyRow = Math.floor(emptyIndex / GRID_SIZE);
      const emptyCol = emptyIndex % GRID_SIZE;
      const neighbors = [];
      if (emptyRow > 0) neighbors.push(emptyIndex - GRID_SIZE);
      if (emptyRow < GRID_SIZE - 1) neighbors.push(emptyIndex + GRID_SIZE);
      if (emptyCol > 0) neighbors.push(emptyIndex - 1);
      if (emptyCol < GRID_SIZE - 1) neighbors.push(emptyIndex + 1);
      
      const randomNeighbor = neighbors[Math.floor(Math.random() * neighbors.length)];
      pieces[emptyIndex] = pieces[randomNeighbor];
      pieces[randomNeighbor] = -1;
      emptyIndex = randomNeighbor;
    }
    moves = 0;
    gameStarted = false;
    renderPuzzle();
  }

  function resetPuzzle() {
    initPuzzle();
    shufflePuzzle();
    moves = 0;
    gameStarted = false;
    document.getElementById('message').textContent = '';
  }

  function checkWin() {
    let win = true;
    for (let i = 0; i < pieces.length - 1; i++) {
      if (pieces[i] !== i) { win = false; break; }
    }
    if (win && pieces[pieces.length - 1] === -1) {
      document.getElementById('message').textContent = '🎉 ¡Completado en ' + moves + ' movimientos! 🎉';
      setTimeout(function() {
        nextImage();
        document.getElementById('message').textContent = '🔄 Nueva imagen cargada. ¡A resolver!';
      }, 1500);
    }
  }

  window.onload = function() {
    initPuzzle();
    shufflePuzzle();
  };
</script>
        

💜 Y eso sería todo. Dice mi hermana que les diga que si les da flojera buscar los colores, se los pidan a la IA, pero les juro que la tortura vale la pena. ✨

💜 Hecho con cariño para la comunidad 💜

No hay comentarios.:

Publicar un comentario