OSDN Git Service

chore: update lib
[delesterandomselector/DelesteRandomSelector.git] / src / com / ranfa / lib / calc / FanCalc.java
1 /*
2  * Copyright 2022 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.ranfa.lib.calc;
18
19 import java.math.BigDecimal;
20 import java.math.RoundingMode;
21 import java.util.concurrent.CompletableFuture;
22 import java.util.concurrent.ExecutorService;
23 import java.util.concurrent.Executors;
24 import java.util.concurrent.atomic.AtomicBoolean;
25 import java.util.concurrent.atomic.AtomicInteger;
26
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 import com.ranfa.lib.concurrent.CountedThreadFactory;
31
32 /**
33  * ファン計算用とのライブラリ
34  * ファン数計算とスコア計算を実装
35  * @author hizum
36  * 
37  * @since 4.0.0
38  */
39 public class FanCalc {
40         
41         // Logger
42         private static final Logger logger = LoggerFactory.getLogger(FanCalc.class);
43         /** 
44          * 非同期処理用のスレッドプール
45          */
46         private static final ExecutorService async = Executors.newCachedThreadPool(new CountedThreadFactory(() -> "DRS", "FanCalcThread", false));
47         
48         /**
49          * 計算式は
50          * 端数切り上げ(スコア*0.001*ルーム補正値*センター、ゲスト効果補正値*プロデュース方針補正値)
51          * ルーム、センター、ゲスト、プロデュース方針の補正値は百分率。計算時に自動で変換します
52          * 
53          * @param score ライブで獲得したスコアを入力します
54          * @param room ルームアイテムによる補正値を百分率のまま(xxx%)入力します
55          * @param center センター、ゲスト効果による補正値を百分率のまま入力します
56          * @param produce プロデュース方針による補正値を百分率のまま入力します
57          * @param premium プレミアムパスによる補正値を百分率のまま入力します
58          * 
59          * @return 一人あたりの獲得ファン数。1回のライブで獲得出来るファン数はこの値の5倍です
60          */
61         public static int fan(int score, int room, int center, int produce, int premium) {
62         BigDecimal toPercent = new BigDecimal(100);
63         BigDecimal res = new BigDecimal(0);
64         BigDecimal roomPercent = new BigDecimal(room).divide(toPercent);
65         BigDecimal centerPercent = new BigDecimal(center).divide(toPercent);
66         BigDecimal producePercent = new BigDecimal(produce).divide(toPercent);
67         BigDecimal premiumPercent = new BigDecimal(premium).divide(toPercent);
68         BigDecimal corrections = new BigDecimal(-1)
69                         .add(roomPercent)
70                         .add(centerPercent);
71         res = res.add(new BigDecimal(score))
72                         .multiply(corrections)
73                         .divide(new BigDecimal("1000"));
74         res = res.setScale(0,RoundingMode.UP);
75         BigDecimal resCorrected = res.multiply(producePercent);
76         resCorrected = resCorrected.setScale(0,RoundingMode.UP);
77         BigDecimal resPremiumed = resCorrected.multiply(premiumPercent);
78         resPremiumed = resPremiumed.setScale(0, RoundingMode.UP);
79         return (resPremiumed.compareTo(BigDecimal.ZERO) == 0) || (resPremiumed == null) ? 0 : Integer.parseInt(resPremiumed.toString());
80     }
81         
82         /**
83          * 計算式は
84          * 端数切り上げ(スコア*0.001*ルーム補正値*センター、ゲスト効果補正値*プロデュース方針補正値)
85          * ルーム、センター、ゲスト、プロデュース方針の補正値は百分率。計算時に自動で変換します
86          * 
87          * @param score スコア
88          * @param room ルーム補正値
89          * @param center センターアイドル補正値
90          * @param produce プロデュース方針補正値
91          * @param premium プレミアムパス補正値
92          * 
93          * @return 一人当たりの獲得ファン数がラップされているCompletableFuture
94          */
95         public static CompletableFuture<Integer> fanAsync(int score, int room, int center, int produce, int premium) {
96                 return CompletableFuture.supplyAsync(() -> fan(score, room, center, produce, premium), async);
97         }
98         
99         /**
100          * 目標スコアを計算。
101          * 初期実装の思想は並列処理による再帰計算。
102          * 
103          * @param fan 目標ファン
104          * @param multiplier LIVEの繰り返し回数
105          * @param room ルームアイテム補正値(百分率)
106          * @param center センター、ゲスト効果による補正値
107          * @param produce プロデュース方針にとる補正値
108          * @param premium プレミアムパスによる補正値
109          * 
110          * @return LIVE一回当たりの目標スコアがラップされているCompletableFuture
111          */
112         public static CompletableFuture<Integer> scoreAsync(int fan, int multiplier, int room, int center, int produce, int premium) {
113                 return CompletableFuture.supplyAsync(() -> score(fan, multiplier, room, center, produce, premium), async);
114         }
115         
116         /**
117          * 目標スコアを計算。
118          * 初期実装の思想は並列処理による再帰計算。
119          * 
120          * @param fan 目標ファン
121          * @param multiplier LIVEの繰り返し回数
122          * @param room ルームアイテム補正値(百分率)
123          * @param center センター、ゲスト効果による補正値
124          * @param produce プロデュース方針にとる補正値
125          * @param premium プレミアムパスによる補正値
126          * 
127          * @return LIVE一回当たりの目標スコア
128          */
129         private static int score(int fan, int multiplier, int room, int center, int produce, int premium) {
130                 BigDecimal goalFan = new BigDecimal(fan).divide(new BigDecimal(multiplier), 0, RoundingMode.UP);
131                 final AtomicInteger result = new AtomicInteger(0);
132                 final AtomicBoolean flag = new AtomicBoolean(false);
133                         logger.info("Started to calculate score at dedicated thread.");
134                         while(!flag.get()) {
135                 int localFan = fan(result.incrementAndGet(), room, center, produce, premium) * 5;
136                 if(goalFan.compareTo(new BigDecimal(localFan)) <= 0) {
137                     flag.set(true);
138                 }
139             }
140                         logger.info("Finished calculating. Estimated Fan value : {}", result.intValue());
141                 return Integer.parseInt(result.toString());
142         }
143         
144
145 }