fe-interview
fe-interview copied to clipboard
[js] 第155天 用js模拟实现微信抢红包的算法,并说明你的思路
第155天 用js模拟实现微信抢红包的算法,并说明你的思路
开个监听器,找到红包消息对应的特征,进而可以监听红包消息,然后在这个回调函数里面写入打开红包的代码,当然,单纯的js肯定实现不了,需要调用别的语言和api接口
普惠红包
除了最后一人,其他每个人随机范围为 (0, 20),也相当于每人平均 10 块吧。 可以再打乱一次顺序来避免最后一人问题。
function grabMoney(total, maxTimes) {
// 结果数组 剩余次数 剩余金额
var res = [], times = maxTimes, rest = total;
while (--times > 1) {
var r = random(0, rest / times * 2);
var _r = r.toFixed(2).replace('.', ''); // 处理双精度运算问题
var _rest = rest.toFixed(2).replace('.', '');
rest = (_rest - _r) / 100;
r = parseFloat(r.toFixed(2));
res.push(r);
}
res.push(rest);
return res;
}
耗时红包
每人随机范围为 (0, 25),超出总价就重新排,低于总价则平摊。 由于有除法,余数计算误差大,所以系统会贪掉一丢丢。
function grabMoney(total, maxTimes) {
var res = new Array(maxTimes);
var grabed = 0;
for (var i=0; i<res.length; i++) {
var r = random(0, total / 4);
r = parseFloat(r.toFixed(2));
grabed += r;
if (grabed > total) return grabMoney(total, maxTimes);
res[i] = r;
}
if (grabed < total) {
var average = (total - grabed) / total;
res = res.map(function(item) {
return item + average;
});
}
return res;
}
/**
* 抢红包算法
* @param {*} money 红包金额数
* @param {*} people 红包人数
*/
function drawLucky (money, people) {
let remainMoney = money
let remainPeople = people
return {
// 每一次抢到的红包金额
draw () {
let per = remainMoney / remainPeople
let curMoney = 0
if (remainPeople === 1) {
curMoney = Math.round(remainMoney * 100) / 100 // 使数字保留两位小数
remainPeople--
} else if (remainPeople > 1) {
curMoney = Math.round(per * (Math.random() * 1.6 + 0.2) * 100) / 100 // 使数字保留两位小数【随机分配剩余金额,份数为(0.2, 1.8)之间】
remainPeople--
}
remainMoney -= curMoney
return curMoney
}
}
}
let test = drawLucky(100, 20)
let amount = 0
for (let i = 0; i < 20; i++) {
let cur = test.draw()
amount += cur
console.log(cur)
}
console.log(amount)
感觉真实情况下还要知道实时剩余人数和金额,考虑到网络情况,有点难;
参考 https://www.jianshu.com/p/11494478a7e9
I decided to use closure to solve this problem. When creating red pockets, users will be asked to provide three arguments. The first argument is the total amount of money they want to put into the red pockets. The second argument is the number of red pockets. The third argument indicates whether the amount of money in each red pocket is determined randomly. When createRedPockets is called, an array of red pockets (positive numbers) will be created and a function is returned. The function returns a red pocket when there are still red pockets (positive numbers) left in the array. Otherwise, it returns 0.
const createRedPockets = (total, num = 1, random = false) => { let redPockets; if (random) { let weights = []; for (let i = 0; i < num; i++) { weights.push(Math.random() + 1); } const sum = weights.reduce((a, b) => a + b); weights = weights.map(weight => weight / sum); redPockets = weights.map(weight => weight * total); } else { redPockets = Array(num).fill(total / num); } return () => { if (!redPockets.length) return 0; return redPockets.pop(); }; };
function getRandomMoney(remainMoney,remainSize){ let moneyList=[]; const min=0.01; let max,money; while (remainSize>1){ max=remainMoney/remainSize*2; money=Math.random()max; money=money<0.01 ? 0.01 : money; money=Math.round(money100)/100; moneyList.push(money); remainSize--; remainMoney-=money; }
moneyList.push(Math.round(remainMoney*100)/100); return moneyList; } const maxMoney=100; //红包总金额 const maxSize=20; //红包个数 console.log(getRandomMoney(maxMoney,maxSize))