如何用 js 实现一个类似微信红包的随机算法
如何用 js 实现一个类似微信红包的随机算法
js, 微信红包, 随机算法

"use strict";
/**
*
* @author xgqfrms
* @license MIT
* @copyright xgqfrms
* @created 2020-09-16
* @modified
*
* @description 如何用 js 实现一个类似微信红包的随机算法, 最简单的方法实现微信红包的随机算法
* @difficulty Hard
* @complexity O(n)
* @augments
* @example
* @link https://www.cnblogs.com/xgqfrms/p/13689802.html
* @link https://www.cnblogs.com/xgqfrms/tag/%E7%BA%A2%E5%8C%85/
* @link https://www.zhihu.com/question/22625187/answer/1478941580
* @solutions
*
*/
const log = console.log;
const shuffle = (arr = []) => {
let len = arr.length;
while (len > 1){
const index = Math.floor(Math.random() * len--);
[
arr[len],
arr[index],
] = [
arr[index],
arr[len],
];
}
return arr;
}
/**
算法需要满足条件:
1. 每个人都可以分到至少 0.01 元;
2. 所有人的分到的红包之和与发出的金额相等,不多不少,刚好分完;
3. 每个人分到金额的概率相等;
*/
/**
假设,发出一个 100元红包,给 10个人分!
算法实现:
1. 按照人数,生成一个等长的数组,且每一个元素的初始化值为 0.01;
2. 将剩余的金额(100 - 10 * 0.01), 按照微信设计的规则(假如是正态分布)进行分配出 10 份;
3. 将分配好的红包,依次加入到生成的数组中;
4. 最后使用 shuffle 算法打乱数组,并返回;
5. 将计算好的数组,按照抢红包的顺序作为索引值依次取出红包即可.
*/
// 精度损失解决方案, 扩大后,再还原
const autoRandomRedPackage = (money, num, limit = 0.01) => {
if((money / num) < limit) {
// alert
log(` 请重新输入红包数量! 减少红包数量,或增加红包金额!`);
log(` 你输入的红包数量太多了,每个人至少要能分到 0.01 元!`);
return false;
} else {
const originMoney = money;
const originLimit = limit;
let multi = 100 * (100 / money);
money *= multi;
limit *= multi;
// log(`multi =`, multi);
const result = [...new Uint8Array(num)].fill(limit, 0, num);
// 1. 将剩余的红包,均分,如果有余数,随机的添加到数组的一个元素上
const restLimit = (money - limit * num) / limit;
const reminderLimit = (restLimit % num);
const reminderMoney = reminderLimit * limit;
const averageLimit = (restLimit - reminderLimit) / num;
for (let i = 0; i < num; i++) {
const index = parseInt(Math.random() * averageLimit);
const randomMoney = index * limit;
const leftMoney = (averageLimit - index) * limit;
// 2. 在平均后的范围内,计算出一个随机数,将分配好的红包,依次加入到生成的数组中;
result[i] += randomMoney;
// 3. 分配后剩余的红包,随机加入到生成的数组中;
const j = parseInt(Math.random() * num);
result[j] += leftMoney;
}
// 4. 将平均后的余数红包,随机加入到生成的数组中;
if(reminderMoney > 0) {
const index = parseInt(Math.random() * num);
result[index] += reminderMoney;
}
const temp = shuffle(result).map(i => i / multi);
// log(`temp =`, temp);
const total = temp.reduce((acc, i) => acc += i*multi, 0) / multi;
// log(`total !== originMoney`, total !== originMoney, total, originMoney);
if(total !== originMoney) {
return autoRandomRedPackage(originMoney, num, originLimit);
}
const [min, ...rest1] = temp.sort((a, b) => a - b > 0 ? 1 : -1);
const [max, ...rest2] = temp.sort((a, b) => a - b > 0 ? -1 : 1);
return {
total: total,
result: temp,
desc: `
如何用 js 实现一个类似微信红包的随机算法的更多相关文章
- 如何用 js 实现一个 class 类函数
如何用 js 实现一个 class 类函数 原理 实现方式 总结 refs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refere ...
- 如何用 js 实现一个 apply 函数
如何用 js 实现一个 apply 函数 原理 实现方式 总结 refs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referen ...
- 如何用 js 实现一个 call 函数
如何用 js 实现一个 call 函数 原理 实现方式 总结 refs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referenc ...
- 如何用 js 实现一个 sleep 函数
如何用 js 实现一个 sleep 函数 原理 实现方式 总结 refs js sleep xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!
- 如何用 js 实现一个 new 函数
如何用 js 实现一个 new 函数 原理 new 关键字实现经过了如下过程 创建一个空对象 obj = {} 链接到原型 obj.proto = constructor.prototype 绑定 t ...
- 如何用 js 实现一个 bind 函数
如何用 js 实现一个 bind 函数 原理 实现方式 总结 refs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referenc ...
- 说说如何用js实现一个模板引擎
本文同步更新在: https://github.com/whxaxes/blog/issues/4 ,在 github 看文章显示效果会更好一些. 前言 不知不觉就很长时间没造过什么轮子了,以前一直想 ...
- Qt 做一个类似微信滑动聊天界面的demo
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://www.cnblogs.com/lihuidashen/p/115889 ...
- 使用React.js写一个类似单选框与复选框的功能
单选框 <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <tit ...
随机推荐
- (04)-Python3之--字典(dict)操作
1.定义 字典的关键字:dict 字典由多个键和其对应的值构成的 键-值 对组成,每个键值对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中. {key1:value1 ...
- Linux安装redis报错:jemalloc/jemalloc.h: No such file or directory踩坑
报错内容: 针对这个错误,我们可以在README.md 文件中看到解释: --------- Selecting a non-default memory allocator when buildin ...
- js中的事件委托(事件代理)详解
本文转载:https://www.cnblogs.com/liugang-vip/p/5616484.html#!comments js中的事件冒泡.事件委托是js 中一些需要注意的小知识点,这里结合 ...
- Bitter.Core系列四:Bitter ORM NETCORE ORM 全网最粗暴简单易用高性能的 NETCore ORM 之 示例 查询
一: 单表模型驱动查询 如下示例代码演示: // 根据ID 查询: var studentquery = db.FindQuery<TStudentInfo>().QueryById(12 ...
- 3分钟搞懂什么是WPF。
先推荐下猛哥(刘铁猛)的书籍 <深入浅出WPF>. 一直以来,完美的用户体验是桌面应用程序和Web应用程序中的一大障碍.许多开发人员绞尽脑汁将界面设计得美观炫丽些.互 动感强些,但费了九 ...
- 数位dp 笔记
目录 数位dp 笔记 解决的问题 & 主体思想 入门 -- windy数 绕一个弯 -- 萌数 the end? -- 恨7不成妻 小心细节 [SDOI2016]储能表 复杂度起飞 [AHOI ...
- linux下mysql基于mycat做主从复制和读写分离之基础篇
Linux下mysql基于mycat实现主从复制和读写分离1.基础设施 两台虚拟机:172.20.79.232(主) 172.20.79.233(从) 1.1软件设施 mysql5.6.39 , my ...
- Kubernetes --(k8s) service
service Kubernete Service 是一个定义了一组Pod的策略的抽象,我们也有时候叫做宏观服务.这些被服务标记的Pod都是(一般)通过label Selector决定的 对于Kube ...
- python实现经典排序算法
以下排序算法最终结果都默认为升序排列,实现简单,没有考虑特殊情况,实现仅表达了算法的基本思想. 冒泡排序 内层循环中相邻的元素被依次比较,内层循环第一次结束后会将最大的元素移到序列最右边,第二次结束后 ...
- 【BFS】hdu 1973 Prime Path
题目描述: http://poj.org/problem?id=3414 中文大意: 使用两个锅,盛取定量水. 两个锅的容量和目标水量由用户输入. 允许的操作有:灌满锅.倒光锅内的水.一个锅中的水倒入 ...