如何用 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 实现一个类似微信红包的随机算法的更多相关文章

  1. 如何用 js 实现一个 class 类函数

    如何用 js 实现一个 class 类函数 原理 实现方式 总结 refs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refere ...

  2. 如何用 js 实现一个 apply 函数

    如何用 js 实现一个 apply 函数 原理 实现方式 总结 refs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referen ...

  3. 如何用 js 实现一个 call 函数

    如何用 js 实现一个 call 函数 原理 实现方式 总结 refs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referenc ...

  4. 如何用 js 实现一个 sleep 函数

    如何用 js 实现一个 sleep 函数 原理 实现方式 总结 refs js sleep xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  5. 如何用 js 实现一个 new 函数

    如何用 js 实现一个 new 函数 原理 new 关键字实现经过了如下过程 创建一个空对象 obj = {} 链接到原型 obj.proto = constructor.prototype 绑定 t ...

  6. 如何用 js 实现一个 bind 函数

    如何用 js 实现一个 bind 函数 原理 实现方式 总结 refs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referenc ...

  7. 说说如何用js实现一个模板引擎

    本文同步更新在: https://github.com/whxaxes/blog/issues/4 ,在 github 看文章显示效果会更好一些. 前言 不知不觉就很长时间没造过什么轮子了,以前一直想 ...

  8. Qt 做一个类似微信滑动聊天界面的demo

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://www.cnblogs.com/lihuidashen/p/115889 ...

  9. 使用React.js写一个类似单选框与复选框的功能

    单选框 <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <tit ...

随机推荐

  1. Certbot CA 证书 https

    certbot (base) a@test:~# certbot --help - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ...

  2. Service Mesh 在百度网盘数万后端的落地实践

    https://www.infoq.cn/article/vpa6aypkizuqiijzflih

  3. Kubernetes TensorFlow 默认 特定 集群管理器 虚拟化技术

    Our goal is to foster an ecosystem of components and tools that relieve the burden of running applic ...

  4. js控制页面元素值

    // TODO id 定位 var ele1 = document.getElementById("test1"); // alert(ele1.value) // TODO 根据 ...

  5. SpringMVC听课笔记(三:使用@RequestMapping映射请求)

    1. Spring MVC使用 @RequestMapping 注解为控制器指定可以处理哪些URL请求 2. 标注点: --类定义处:提供初步的请求映射信息.相对于WEB应用的根目录 --方法处:提供 ...

  6. Springboot 项目部署到服务器上

    项目部署到服务器上,有两种方式,一种 jar 包,一种 war 包 jar包 部署时,后续的域名配置,SSL证书等在nginx中配置 war包 部署时,后续的域名配置可以在tomcat中配置就好,修改 ...

  7. CCF-最优配餐(BFS)

    最优配餐   问题描述 栋栋最近开了一家餐饮连锁店,提供外卖服务.随着连锁店越来越多,怎么合理的给客户送餐成为了一个急需解决的问题.栋栋的连锁店所在的区域可以看成是一个n×n的方格图(如下图所示),方 ...

  8. 一周精彩内容分享(第 1 期):"世纪逼空大战"

    这里记录过去一周,我看到的值得分享的东西. 一方面是整理记录一下自己一周的学习,另一方面也是期待自己有更多的输出,有更多的价值. 周刊开源(Github:wmyskxz/weekly),欢迎提交 is ...

  9. 2019牛客暑期多校训练营(第十场)E-Hilbert Sort(分形)

    >传送门< 题意 现给出你 $n $个坐标和 $k$,让你根据$ k$阶 希尔伯特曲线的走向排列给出的 $n $个坐标 希尔伯特曲线如下:  $k=1$ $k=2$ $k=3$可以将边长为 ...

  10. AtCoder Beginner Contest 171

    比赛链接:https://atcoder.jp/contests/abc171/tasks A - αlphabet 题意 给出一个字母,如果为大写输出 'A',如果为小写输出 'a' . 代码 #i ...