在一次工作中,产品有这样一个需求,用户输入数据。原价:x、底价:y,帮砍人数:n,当第n个人点击砍价时,用户恰好砍完,到达底价。由于各种限制,第一版比较匆忙,我们很简单,直接采取简单粗暴的方法,直接每人砍的数目为 (x - y )/ n;后台使用golang开发,代码很简单(小学生代码):
//计算可以砍价的值 Priprice, err := strconv.Atoi(rule.Priprice) LatPrice, err := strconv.Atoi(rule.LatPrice) MaxJoiners, err := strconv.Atoi(rule.MaxJoiners) resul := (Priprice - LatPrice) / MaxJoiners // 计算当前用户减去后的价格 actjoindetail.Current = actjoindetail.Current - resul // 判断是否已经砍到底价 if actjoindetail.Current <= LatPrice { actjoindetail.Current = LatPrice actjoindetail.Results = "success" }
以上代码还有一个bug,当resul 是无限小数时,我们可能会看到的是第n + 1 个人才能砍到低价。因为数据实在太小,所以第n + 1 个人的体验不会太好。
当时还想了一种其他的方式,使用 平均值resul:(x - y )/ n,对于第o个用户,o为奇数时,每次砍价为 (1 + 随机数 )* resul ; 偶数时为(1 - 随机数) * resul ;很明显,经过一番测试,这是不可信的,随机数并不随机,而且无法满足第n个人砍到低价。即使n 再大也无法满足,随机数并不很随机(此处只是盗用这句话,与主题关系不大)。
第一版结束后,一直将这一代码优化的想法留在脑海。这一需求的原理其实与拼手气红包是一致的,在一次闲下来之后,查阅了相关资料,在知乎看到了一篇回答。据说是微信官方代码。
因为版权限制,知乎无法转载,因此,感兴趣的小伙伴可以点击 链接 查看。
以此为模板,我自己尝试使用JavaScript重新编写了一下代码;
代码如下所示:
// 定义初始变量
// remainSize:剩余人数
// remainMoney : 剩余的金钱
let leftMoneyPackage = {
remainSize:5, // 可自行修改
remainMoney:10, // 原价,可自行修改
};
function getRandomMoney(_leftMoneyPackage){
// 当只有最后一人时
if(_leftMoneyPackage.remainSize === 1){
_leftMoneyPackage.remainSize --;
return Math.round(parseFloat(_leftMoneyPackage.remainMoney)*100)/100;
}
const ran = Math.random();
const min = 0.01;
const max = _leftMoneyPackage.remainMoney / _leftMoneyPackage.remainSize * 2;
let money = ran.toFixed(2) * max;
money = money > 0.01 ? money : 0.01;
money = Math.round(parseFloat(money)*100)/100;
_leftMoneyPackage.remainSize --;
_leftMoneyPackage.remainMoney -= money;
console.log(_leftMoneyPackage)
return money;
}
结语:拼手气红包的代码不是那么的难,从实现的角度来讲,其根本源码就这么几行,遇到问题主要还是要多思考,代码也会更简单.