学生抽取

当前算法: 独立随机
点击开始

抽取记录

暂无记录

学生列表

学生数量: 0

分组设置

学生列表

学生数量: 0
点击"生成分组"开始分组

关于本网站

本网站采用加密安全的随机数生成算法,确保每次抽取结果完全随机、公平公正。 我们使用浏览器内置的 crypto.getRandomValues() API,这是基于硬件熵源的 密码学安全随机数生成器,保证了结果的不可预测性。

随机数生成器

// 使用加密安全的随机数生成器(借鉴 wheelofnames.com)
function getSecureRandom() {
    if (window.crypto && window.crypto.getRandomValues) {
        const array = new Uint32Array(1);
        window.crypto.getRandomValues(array);
        return array[0] / (0xFFFFFFFF + 1);
    }
    return Math.random();
}

说明crypto.getRandomValues() 使用浏览器提供的加密安全随机数生成器, 基于硬件熵源(如鼠标移动、键盘输入延迟、系统时钟等)生成真正不可预测的随机数。 通过将随机数除以最大值,确保每个学生被选中的概率完全相等。

三种随机算法

1. 独立随机(Independent Random)

完全随机模式,每次抽取都是独立事件,每个学生被选中的概率完全相等。这是最公平的随机算法,适合需要绝对公平的场景。

// 独立随机算法
function selectStudent() {
    // 完全随机选择,每个学生概率相等
    return Math.floor(getSecureRandom() * students.length);
}
  • 特点:每次抽取都是独立事件,之前的结果不会影响后续抽取
  • 适用场景:需要绝对公平的随机抽取,如抽奖、随机点名等
  • 概率分布:每个学生被选中的概率 = 1 / 学生总数

2. 雨露均沾(Fair Distribution)

智能分配模式,尽可能保证所有学生都会被抽到,且不会连续抽取同一个人。系统会记录每个学生的被抽中次数,优先选择被抽中次数较少的学生。

// 雨露均沾算法
function selectStudent() {
    // 排除上次被抽中的学生
    const availableStudents = students
        .map((student, index) => ({ 
            student, index, 
            count: studentPickCounts[student] || 0 
        }))
        .filter(item => item.index !== lastPickedIndex);
    
    // 找到被抽中次数最少的学生
    const minCount = Math.min(...availableStudents.map(item => item.count));
    const candidates = availableStudents.filter(item => item.count === minCount);
    
    // 从候选者中随机选择一个
    const selected = candidates[Math.floor(getSecureRandom() * candidates.length)];
    
    // 更新计数
    studentPickCounts[selected.student] = (studentPickCounts[selected.student] || 0) + 1;
    lastPickedIndex = selected.index;
    
    return selected.index;
}
  • 特点:优先选择被抽中次数最少的学生,确保所有学生都有机会被抽到
  • 防重复:不会连续两次抽取同一个学生
  • 适用场景:需要确保所有学生都能被抽到的场景,如课堂提问、任务分配等
  • 公平性:长期来看,每个学生被抽中的次数会趋于相等

3. 均衡模式(Balanced Mode)

平衡随机模式,在保证随机性的同时,适度考虑历史记录。既保持随机性,又避免某些学生长期不被抽中。使用加权随机算法,被抽中次数越少的学生权重越高。

// 均衡模式算法
function selectStudent() {
    // 计算每个学生的权重
    const weights = students.map((student, index) => {
        const count = studentPickCounts[student] || 0;
        // 如果上次被抽中,权重降低(避免连续抽取)
        const penalty = (index === lastPickedIndex) ? 0.3 : 1.0;
        // 被抽中次数越少,权重越高(使用倒数)
        return (1 / (count + 1)) * penalty;
    });
    
    // 计算总权重
    const totalWeight = weights.reduce((sum, w) => sum + w, 0);
    
    // 加权随机选择
    let random = getSecureRandom() * totalWeight;
    let selectedIndex = 0;
    for (let i = 0; i < weights.length; i++) {
        random -= weights[i];
        if (random <= 0) {
            selectedIndex = i;
            break;
        }
    }
    
    // 更新计数
    studentPickCounts[students[selectedIndex]] = 
        (studentPickCounts[students[selectedIndex]] || 0) + 1;
    lastPickedIndex = selectedIndex;
    
    return selectedIndex;
}
  • 特点:在随机性和公平性之间取得平衡,既保持随机性,又避免长期忽略某些学生
  • 权重机制:被抽中次数越少,权重越高(权重 = 1 / (被抽中次数 + 1))
  • 防连续:上次被抽中的学生权重会降低30%,减少连续抽取的概率
  • 适用场景:需要平衡随机性和公平性的场景,如分组、任务分配等
  • 优势:相比"雨露均沾"更随机,相比"独立随机"更公平

注意:本系统不使用标准的 Math.random(), 而是采用更高安全级别的加密随机数生成器,确保结果的真实随机性。 所有算法都基于 getSecureRandom() 函数,保证了底层随机数的安全性。