模仿微信发红包

论坛 期权论坛 脚本     
匿名技术用户   2020-12-27 00:29   11   0

微信发红包的金额总是不固定的,因此今天特意好奇一下,能不能使用Java代码进行模仿呢?

以下是完整的代码演示,如果不需要其中的数据分析,可以去掉,去掉之后的jdk版本不做过多的要求,没去掉之前,要求是1.8+:

package com.demo;

import java.util.Arrays;

/**
 * 大致模仿微信发红包的金额
 * @author 小书包
 * @date 2018年10月13日13:26:32
 */
public class RedPocket {

 /**
  * 红包的初始化,每位用户分配到的为平均金额
  * @param money 总金额
  * @param pocketNum 红包数量
  * @param current 当前是第几次
  */
 private double[] calcuPocket(double money, int pocketNum) {
  if ((pocketNum + 1) * 0.01 >= money) {
   System.out.println("红包的最低金额为0.01元");
   return null;
  }
  // 用于存储当前已分配的金额总数
  double sum = 0;
  double[] pockets = new double[pocketNum];
  // 进行红包金额的初始化,每个人给出的金额为平均值
  for (int i = 0; i < pocketNum; i++) {
   pockets[i] = (double) Math.round((money / pocketNum) * 100) / 100;
   // 出现这个判断是为了防止有的数除不掉,发的红包与金额总数不匹配,因此将最后剩下的全给最后一个
   if (i == pocketNum - 1) {
    pockets[i] = (double) Math.round((money - sum) * 100) / 100;
   }
   sum = sum + pockets[i];
  }
  return pockets;
 }

 /**
  * 分析平均值的分布规律和方差的大致的分布
  * @param current 当前位置
  * @param pockets 红包数组
  * @param average 平均值
  */
 private void analysisByMathMethod(int current, double[] pockets, double average) {
  System.out.print("第" + current + "次:");
  int count = 0;
  for (double pocket : pockets) {
   System.out.print(pocket + " ");
   if (pocket == average)
    count++;
  }
  System.out.print("\t平均值为:" + average);
  System.out.print("\t获得最小值为:" + Arrays.stream(pockets).reduce(Double::min).getAsDouble());
  System.out.print("\t获得最大值为:" + Arrays.stream(pockets).reduce(Double::max).getAsDouble());
  System.out.print("\t存在" + count + "个与平均值相同的元素!");
  double result = calcuVariance(average, pockets);
  System.out.print("\t方差为:" + result);
  System.out.println();
 }

 /**
  * 传递一个平均值和数组,用以计算数组中的值的方差分布
  * @param average 平均值
  * @param pockets 待计算方差的数组
  * @return
  */
 private double calcuVariance(double average, double[] pockets) {
  double result = 0;
  for (double pocket : pockets) {
   result = result + Math.pow(pocket - average, 2);
  }
  result = result / pockets.length;
  return result;
 }

 /**
  * 随机进行红包的分布
  * @param pockets 存放红包的数组
  * @return
  */
 private double[] changePosition(double[] pockets) {
  int length = pockets.length;
  // 表示当前的次数,用于计算需要随机多少次,随机次数越多,方差越大
  int count = 0;
  while (count < length * 10) {
   // 随机从数组中挑选一个进行金额的减少
   int start = (int) (Math.random() * length);
   // 随机从数组中挑选一个进行金额的添加
   int end = (int) (Math.random() * length);
   // 减少的金额根据挑选的值进行变化
   double sub = (double) Math.round(Math.random() * 100 * pockets[start]) / 100;
   pockets[start] = (double) Math.round((pockets[start] - sub) * 100) / 100;
   // 如果减少后的金额少于0.01,那么就不减少,重新挑选值进行分配
   if (pockets[start] <= 0.01) {
    pockets[start] = (double) Math.round((pockets[start] + sub) * 100) / 100;
    continue;
   }
   pockets[end] = (double) Math.round((pockets[end] + sub) * 100) / 100;
   count++;
  }
  return pockets;
 }


 public static void main(String[] args) {
  RedPocket pocket = new RedPocket();
  int money = 100;
  int pocketNum = 99;
  // 进行计算1000次,根据结果可简单的分析出红包金额的分布范围,最小与最大的红包差会变大,基本符合微信红包的规则
  for (int current = 0; current < 1000; current++) {
   double[] pockets = pocket.calcuPocket(money, pocketNum);
   if (pockets!=null) {
    // 进行红包的随机分布
    pockets = pocket.changePosition(pockets);
    // 获得大概的平均值
    double average = (double) Math.round((money / pocketNum) * 100) / 100;
    pocket.analysisByMathMethod(current, pockets, average);
   }
  }
 }
}

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP