OSDN Git Service

add tests
[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.newCachedThreadPool(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) ? 0 : Integer.parseInt(resPremiumed.toString());
56     }
57         
58         public static CompletableFuture<Integer> fanAsync(int score, int room, int center, int produce, int premium) {
59                 return CompletableFuture.supplyAsync(() -> fan(score, room, center, produce, premium), async);
60         }
61         
62         /**
63          * 目標スコアを計算。
64          * 初期実装の思想は並列処理による再帰計算。
65          * @param fan 目標ファン
66          * @param multiplier LIVEの繰り返し回数
67          * @param room ルームアイテム補正値(百分率)
68          * @param center センター、ゲスト効果による補正値
69          * @param produce プロデュース方針にとる補正値
70          * @param premium プレミアムパスによる補正値
71          * @return LIVE一回当たりの目標スコア
72          */
73         public static CompletableFuture<Integer> scoreAsync(int fan, int multiplier, int room, int center, int produce, int premium) {
74                 return CompletableFuture.supplyAsync(() -> score(fan, multiplier, room, center, produce, premium), async);
75         }
76         
77         /**
78          * @param fan 目標ファン
79          * @param multiplier LIVEの繰り返し回数
80          * @param room ルームアイテム補正値(百分率)
81          * @param center センター、ゲスト効果による補正値
82          * @param produce プロデュース方針にとる補正値
83          * @param premium プレミアムパスによる補正値
84          * @return LIVE一回当たりの目標スコア
85          */
86         private static int score(int fan, int multiplier, int room, int center, int produce, int premium) {
87                 BigDecimal goalFan = new BigDecimal(fan).divide(new BigDecimal(multiplier), 0, RoundingMode.UP);
88                 final AtomicInteger result = new AtomicInteger(0);
89                 final AtomicBoolean flag = new AtomicBoolean(false);
90                         logger.info("Started to calculate score at dedicated thread.");
91                         while(!flag.get()) {
92                 int localFan = fan(result.incrementAndGet(), room, center, produce, premium) * 5;
93                 if(goalFan.compareTo(new BigDecimal(localFan)) <= 0) {
94                     flag.set(true);
95                 }
96             }
97                         logger.info("Finished calculating. Estimated Fan value : {}", result.intValue());
98                 return Integer.parseInt(result.toString());
99         }
100         
101
102 }