使用 TS 简单实现微信抢红包算法

2022年01月16日

在网上搜索一番后找到了一个微信正统(据说)算法 Java 版本的代码,下面对这个算法进行一下分析:

Java 版本

java 复制代码
public static double getRandomMoney(LeftMoneyPackage _leftMoneyPackage) {
    // remainSize 剩余的红包数量
    // remainMoney 剩余的钱
    if (_leftMoneyPackage.remainSize == 1) {
        _leftMoneyPackage.remainSize--;
        return (double) Math.round(_leftMoneyPackage.remainMoney * 100) / 100;
    }
    Random r     = new Random();
    double min   = 0.01; //
    double max   = _leftMoneyPackage.remainMoney / _leftMoneyPackage.remainSize * 2;
    double money = r.nextDouble() * max;
    money = money <= min ? 0.01: money;
    money = Math.floor(money * 100) / 100;
    _leftMoneyPackage.remainSize--;
    _leftMoneyPackage.remainMoney -= money;
    return money;
}

可以看出核心流程是通过生成一个范围为 0.01 - 平均值*2 的随机数,来作为红包的大小,下面通过 JS 来实现一下:

Typescript 版本

typescript 复制代码
// 这里引用 math.js 数学库用于处理精度问题
import * as math from 'mathjs';

// 封装高精度的加法
function add(num1: number, num2: number) {
	return Number(
		math.chain(math.bignumber(num1)).add(math.bignumber(num2)).done()
	);
}
// 封装高精度的减法
function substract(num1: number, num2: number) {
	return Number(
		math.chain(math.bignumber(num1)).subtract(math.bignumber(num2)).done()
	);
}
// 声明一个红包的类
class LeftMoneyPackage {
	remainSize: number;
	remainMoney: number;
	constructor(remainSize, remainMoney) {
		this.remainSize = remainSize;
		this.remainMoney = remainMoney;
	}
}
// 获取随机金额的函数
function getRandomMoney(leftMoneyPackage: LeftMoneyPackage): number {
	let { remainSize, remainMoney } = leftMoneyPackage;
	if (remainSize === 1) {
		return remainMoney;
	}
	const min = 0.01;
	// 获取最大值
	const max = (remainMoney / remainSize) * 2;
	// 在 0 - max 之间取值,这里进行处理获取一个两位小数
	let money = Math.floor(Math.random() * max * 100) / 100;
	money = money < min ? 0.01 : money;
	leftMoneyPackage.remainSize--;
	leftMoneyPackage.remainMoney = substract(remainMoney, money);
	return money;
}

const leftMoneyPackage = new LeftMoneyPackage(10, 10);

let num = 0;

for (let i = 0; i < 10; i++) {
	const result = getRandomMoney(leftMoneyPackage);
	num = add(num, result);
	console.log(result);
}
console.log(num);

可以看出,该算法本身的逻辑还是比较好理解,唯一需要注意的就是 JS 浮点数运算的精度问题.

相关文章

Vite项目配置本地HTTPS

React Native 开发环境安装踩坑

《JavaScript 高级程序设计》第10-16章