Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

Desafio do amigo secreto

depois de muitos erros meu código ficou assim, diferente do mostrado nas aulas, então decidi postar para talvez ajudar outras pessoas com dificuldade.

function adicionar() {
    let nomeAmigo = document.getElementById('nome-amigo').value.trim();
    if (nomeAmigo === '') {
        alert('Por favor, insira um nome válido.');
        document.getElementById('nome-amigo').value = '';
        return;
    }

    let listaAmgs = document.getElementById('lista-amigos');
    let novoItem = document.createElement('li');
    novoItem.textContent = nomeAmigo;
    listaAmgs.appendChild(novoItem);
    document.getElementById('nome-amigo').value = '';
}
function shuffle(array) {
    let a = array.slice();
    for (let i = a.length - 1; i > 0; i--) {
        let j = Math.floor(Math.random() * (i + 1));
        [a[i], a[j]] = [a[j], a[i]];
    }
    return a;
}
function sortear() {
    let listaAmgs = document.getElementById('lista-amigos');
    let listaNomes = listaAmgs.getElementsByTagName('li');
    let listaSorteio = document.getElementById('lista-sorteio');

    listaNomes = Array.from(listaNomes).map(item => item.textContent);

    if (listaNomes.length <= 2) {
        alert('Adicione pelo menos três nomes antes de sortear!');
        return;
    }

    // nomes idênticos podem causar ambiguidade na comparação; exigir nomes únicos
    if (new Set(listaNomes).size !== listaNomes.length) {
        alert('Existem nomes duplicados. Por favor, use nomes únicos para o sorteio.');
        return;
    }

    // Gera uma permutação onde ninguém recebe o próprio nome (derangement)
    let shuffled;
    let tentativas = 0;
    do {
        shuffled = shuffle(listaNomes);
        tentativas++;
        if (tentativas > 1000) {
            alert('Não foi possível sortear corretamente. Tente novamente.');
            return;
        }
    } while (shuffled.some((v, i) => v === listaNomes[i]));

    let amigosSorteados = {};
    for (let i = 0; i < listaNomes.length; i++) {
        amigosSorteados[listaNomes[i]] = shuffled[i];
    }

    listaSorteio.innerHTML = '';
    for (let amigo in amigosSorteados) {
        let itemSorteio = document.createElement('p');
        itemSorteio.textContent = `${amigo} → ${amigosSorteados[amigo]}`;
        listaSorteio.appendChild(itemSorteio);
    }
}
function reiniciar() {
    let reinicarSorteio = document.getElementById('lista-sorteio');
    reinicarSorteio.innerHTML = '';
    let listaAmgs = document.getElementById('lista-amigos');
    listaAmgs.innerHTML = '';
}

Matricule-se agora e aproveite até 50% OFF

O maior desconto do ano para você evoluir com a maior escola de tecnologia

QUERO APROVEITAR
3 respostas
solução!

Olá, Kevin!
Excelente, seu código está muito bem!
Pode fazer alguns ajustes pontuais.

1 - Evitar repetição de document.getElementById().
Você o usa várias vezes para o mesmo elemento — melhor guardar em variáveis no início das funções. Por exemplo, em adicionar():

function adicionar() {
    const inputNome = document.getElementById('nome-amigo');
    const listaAmigos = document.getElementById('lista-amigos');
    const nomeAmigo = inputNome.value.trim();

    if (!nomeAmigo) {
        alert('Por favor, insira um nome válido.');
        inputNome.value = '';
        return;
    }

    const novoItem = document.createElement('li');
    novoItem.textContent = nomeAmigo;
    listaAmigos.appendChild(novoItem);
    inputNome.value = '';
}

2 - Melhorar legibilidade da lógica do sorteio

O trecho do derangement está certo, mas pode ser encapsulado em uma função específica para tornar o código mais claro:

function gerarDerangement(lista) {
    let tentativa = 0;
    let embaralhado;

    do {
        embaralhado = shuffle(lista);
        tentativa++;
        if (tentativa > 1000) return null; // evita loop infinito
    } while (embaralhado.some((nome, i) => nome === lista[i]));

    return embaralhado;
}

Aí seu sortear() fica mais limpo:

function sortear() {
    const listaAmigos = Array.from(document.getElementById('lista-amigos').getElementsByTagName('li'))
                              .map(item => item.textContent);
    const listaSorteio = document.getElementById('lista-sorteio');

    if (listaAmigos.length < 3) {
        alert('Adicione pelo menos três nomes antes de sortear!');
        return;
    }

    if (new Set(listaAmigos).size !== listaAmigos.length) {
        alert('Existem nomes duplicados. Por favor, use nomes únicos.');
        return;
    }

    const resultado = gerarDerangement(listaAmigos);
    if (!resultado) {
        alert('Não foi possível sortear corretamente. Tente novamente.');
        return;
    }

    listaSorteio.innerHTML = '';
    for (let i = 0; i < listaAmigos.length; i++) {
        const item = document.createElement('p');
        item.textContent = `${listaAmigos[i]} → ${resultado[i]}`;
        listaSorteio.appendChild(item);
    }
}

3 - Melhorar reiniciar()

Você pode simplificar e adicionar um pequeno feedback visual:

function reiniciar() {
    document.getElementById('lista-amigos').innerHTML = '';
    document.getElementById('lista-sorteio').innerHTML = '';
    alert('Sorteio reiniciado!');
}

Opcional - evitar repetição visual.
Se quiser deixar o sorteio mais bonito, poderia criar elementos ul e li também para o resultado, em vez de p, mas isso é mais estético do que técnico.
Bons estudos!

obrigado pelas dicas, com certeza vou usar, achei algumas partes bem mais fáceis de ler.