/** * M002 加权随机算法数值验证 * 模拟 pickOne 逻辑,验证高权重的人中奖概率更高 */ // 模拟状态 const state = { pool: [ { id: '1', name: '张三', weight: 1 }, { id: '2', name: '李四', weight: 1 }, { id: '3', name: '王五', weight: 10 }, // 高权重 { id: '4', name: '赵六', weight: 0 }, // 权重为0,不参与 ], backdoor: { mustWinList: [], excludeList: [], probabilities: { '王五': 10, '赵六': 0 }, }, isDrawing: false, }; function getWeight(name) { if (state.backdoor.probabilities.hasOwnProperty(name)) { return state.backdoor.probabilities[name]; } for (var i = 0; i < state.pool.length; i++) { if (state.pool[i].name === name) { return state.pool[i].weight || 1; } } return 1; } function pickOne() { var candidates = state.pool.slice(); // 过滤排除名单 if (state.backdoor.excludeList.length > 0) { candidates = candidates.filter(function(p) { return state.backdoor.excludeList.indexOf(p.name) === -1; }); } // 过滤权重为0 candidates = candidates.filter(function(p) { return getWeight(p.name) > 0; }); // 必中名单 if (state.backdoor.mustWinList.length > 0) { var intersection = candidates.filter(function(c) { return state.backdoor.mustWinList.indexOf(c.name) !== -1; }); if (intersection.length > 0) { return intersection[Math.floor(Math.random() * intersection.length)]; } } if (candidates.length === 0) return null; var totalWeight = 0; for (var k = 0; k < candidates.length; k++) { totalWeight += getWeight(candidates[k].name); } if (totalWeight === 0) { return candidates[Math.floor(Math.random() * candidates.length)]; } var r = Math.random() * totalWeight; var cumulative = 0; for (var m = 0; m < candidates.length; m++) { cumulative += getWeight(candidates[m].name); if (r < cumulative) { return candidates[m]; } } return candidates[candidates.length - 1]; } // 运行 10000 次模拟 var trials = 10000; var counts = {}; state.pool.forEach(function(p) { counts[p.name] = 0; }); for (var i = 0; i < trials; i++) { var winner = pickOne(); counts[winner.name]++; } console.log('=== M002 加权随机算法数值验证 ===\n'); console.log('权重配置: 张三=1, 李四=1, 王五=10, 赵六=0(排除)'); console.log('期望概率: 张三≈9.1%, 李四≈9.1%, 王五≈90.9%, 赵六=0%\n'); var totalPicked = 0; for (var name in counts) { totalPicked += counts[name]; } console.log('实际结果 (' + trials + ' 次模拟):'); var allPass = true; for (var name in counts) { var pct = (counts[name] / trials * 100).toFixed(1); var w = getWeight(name); var expectedPct = w === 0 ? 0 : (w / 11 * 100).toFixed(1); var pass = w === 0 ? counts[name] === 0 : Math.abs(parseFloat(pct) - parseFloat(expectedPct)) < 3; var icon = pass ? '✅' : '❌'; console.log(icon + ' ' + name + ': 权重=' + w + ', 实际=' + pct + '%, 期望≈' + expectedPct + '%'); if (!pass) allPass = false; } // 验证赵六权重为0不参与 var zhaoLiuZero = counts['赵六'] === 0; console.log('\n' + (zhaoLiuZero ? '✅' : '❌') + ' 权重为0的人(赵六)中奖次数: ' + counts['赵六'] + ' (期望0)'); // 验证必中名单优先级 console.log('\n=== 必中名单优先级验证 ==='); state.backdoor.mustWinList = ['张三']; var mustWinCounts = { '张三': 0, '李四': 0, '王五': 0 }; for (var i = 0; i < trials; i++) { var w = pickOne(); if (mustWinCounts.hasOwnProperty(w.name)) mustWinCounts[w.name]++; } console.log('必中名单=[张三] 时:'); console.log((mustWinCounts['张三'] === trials ? '✅' : '❌') + ' 张三中奖: ' + mustWinCounts['张三'] + '/' + trials + ' (期望100%)'); console.log((mustWinCounts['李四'] === 0 ? '✅' : '❌') + ' 李四中奖: ' + mustWinCounts['李四'] + '/' + trials + ' (期望0%)'); console.log((mustWinCounts['王五'] === 0 ? '✅' : '❌') + ' 王五中奖: ' + mustWinCounts['王五'] + '/' + trials + ' (期望0%)'); // 验证排除名单 console.log('\n=== 排除名单验证 ==='); state.backdoor.mustWinList = []; state.backdoor.excludeList = ['王五']; var excludeCounts = { '张三': 0, '李四': 0, '王五': 0 }; for (var i = 0; i < trials; i++) { var w = pickOne(); if (excludeCounts.hasOwnProperty(w.name)) excludeCounts[w.name]++; } console.log('排除名单=[王五] 时:'); console.log((excludeCounts['王五'] === 0 ? '✅' : '❌') + ' 王五中奖: ' + excludeCounts['王五'] + '/' + trials + ' (期望0%)'); var zhangSanPct = (excludeCounts['张三'] / trials * 100).toFixed(1); var liSiPct = (excludeCounts['李四'] / trials * 100).toFixed(1); console.log((Math.abs(parseFloat(zhangSanPct) - 50) < 3 ? '✅' : '❌') + ' 张三中奖: ' + zhangSanPct + '% (期望≈50%)'); console.log((Math.abs(parseFloat(liSiPct) - 50) < 3 ? '✅' : '❌') + ' 李四中奖: ' + liSiPct + '% (期望≈50%)'); // 重置 state.backdoor.excludeList = []; console.log('\n=== 算法验证汇总 ==='); console.log('加权随机: ' + (allPass ? '✅ 通过' : '❌ 失败')); console.log('权重0排除: ' + (zhaoLiuZero ? '✅ 通过' : '❌ 失败')); console.log('必中优先: ' + (mustWinCounts['张三'] === trials ? '✅ 通过' : '❌ 失败')); console.log('排除生效: ' + (excludeCounts['王五'] === 0 ? '✅ 通过' : '❌ 失败'));