OSDN Git Service

Merge branch 'master' into release/v4.0.0-Beta
[delesterandomselector/DelesteRandomSelector.git] / src / com / ranfa / lib / calc / FanCalc.java
1 package com.ranfa.lib.calc;
2
3 import java.math.BigDecimal;
4 import java.math.RoundingMode;
5 import java.util.concurrent.CompletableFuture;
6 import java.util.concurrent.ExecutorService;
7 import java.util.concurrent.Executors;
8 import java.util.concurrent.atomic.AtomicBoolean;
9 import java.util.concurrent.atomic.AtomicInteger;
10
11 import org.slf4j.Logger;
12 import org.slf4j.LoggerFactory;
13
14 import com.ranfa.lib.concurrent.CountedThreadFactory;
15
16 /**
17  * ファン計算用とのライブラリ
18  * ファン数計算とスコア計算を実装
19  * @author hizum
20  *
21  */
22 public class FanCalc {
23         
24         private static final Logger logger = LoggerFactory.getLogger(FanCalc.class);
25         private static final ExecutorService async = Executors.newSingleThreadExecutor(new CountedThreadFactory(() -> "DRS", "FanCalcThread", false));
26         
27         /**
28          * 計算式は
29          * 端数切り上げ(スコア*0.001*ルーム補正値*センター、ゲスト効果補正値*プロデュース方針補正値)
30          * ルーム、センター、ゲスト、プロデュース方針の補正値は百分率。計算時に自動で変換します
31          * @param score ライブで獲得したスコアを入力します
32          * @param room ルームアイテムによる補正値を百分率のまま(xxx%)入力します
33          * @param center センター、ゲスト効果による補正値を百分率のまま入力します
34          * @param produce プロデュース方針による補正値を百分率のまま入力します
35          * @return 一人あたりの獲得ファン数。1回のライブで獲得出来るファン数はこの値の5倍です
36          */
37         public static int fan(int score, int room, int center, int produce, int premium) {
38         BigDecimal toPercent = new BigDecimal(100);
39         BigDecimal res = new BigDecimal(0);
40         BigDecimal roomPercent = new BigDecimal(room).divide(toPercent);
41         BigDecimal centerPercent = new BigDecimal(center).divide(toPercent);
42         BigDecimal producePercent = new BigDecimal(produce).divide(toPercent);
43         BigDecimal premiumPercent = new BigDecimal(premium).divide(toPercent);
44         BigDecimal corrections = new BigDecimal(-1)
45                         .add(roomPercent)
46                         .add(centerPercent);
47         res = res.add(new BigDecimal(score))
48                         .multiply(corrections)
49                         .divide(new BigDecimal("1000"));
50         res = res.setScale(0,RoundingMode.UP);
51         BigDecimal resCorrected = res.multiply(producePercent);
52         resCorrected = resCorrected.setScale(0,RoundingMode.UP);
53         BigDecimal resPremiumed = resCorrected.multiply(premiumPercent);
54         resPremiumed = resPremiumed.setScale(0, RoundingMode.UP);
55         return (resPremiumed.compareTo(BigDecimal.ZERO) == 0) || (resPremiumed == null) ? 0 : Integer.parseInt(resPremiumed.toString());
56     }
57         
58         /**
59          * 目標スコアを計算。
60          * 初期実装の思想は並列処理による再帰計算。
61          * @param fan 目標ファン
62          * @param multiplier LIVEの繰り返し回数
63          * @param room ルームアイテム補正値(百分率)
64          * @param center センター、ゲスト効果による補正値
65          * @param produce プロデュース方針にとる補正値
66          * @param premium プレミアムパスによる補正値
67          * @return LIVE一回当たりの目標スコア
68          */
69         public static CompletableFuture<Integer> scoreAsync(int fan, int multiplier, int room, int center, int produce, int premium) {
70                 return CompletableFuture.supplyAsync(() -> score(fan, multiplier, room, center, produce, premium), async);
71         }
72         
73         /**
74          * @param fan 目標ファン
75          * @param multiplier LIVEの繰り返し回数
76          * @param room ルームアイテム補正値(百分率)
77          * @param center センター、ゲスト効果による補正値
78          * @param produce プロデュース方針にとる補正値
79          * @param premium プレミアムパスによる補正値
80          * @return LIVE一回当たりの目標スコア
81          */
82         private static int score(int fan, int multiplier, int room, int center, int produce, int premium) {
83                 BigDecimal goalFan = new BigDecimal(fan).divide(new BigDecimal(multiplier), 0, RoundingMode.UP);
84                 final AtomicInteger result = new AtomicInteger(0);
85                 final AtomicBoolean flag = new AtomicBoolean(false);
86                         logger.info("Started to calculate score at dedicated thread.");
87                         while(!flag.get()) {
88                 int localFan = fan(result.incrementAndGet(), room, center, produce, premium) * 5;
89                 if(goalFan.compareTo(new BigDecimal(localFan)) <= 0) {
90                     flag.set(true);
91                 }
92             }
93                 return Integer.parseInt(result.toString());
94         }
95         
96
97 }