2 * Copyright 2022 the original author or authors.
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
8 * https://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.ranfa.lib.calc;
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;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
30 import com.ranfa.lib.concurrent.CountedThreadFactory;
39 public class FanCalc {
42 private static final Logger logger = LoggerFactory.getLogger(FanCalc.class);
46 private static final ExecutorService async = Executors.newCachedThreadPool(new CountedThreadFactory(() -> "DRS", "FanCalcThread", false));
50 * 端数切り上げ(スコア*0.001*ルーム補正値*センター、ゲスト効果補正値*プロデュース方針補正値)
51 * ルーム、センター、ゲスト、プロデュース方針の補正値は百分率。計算時に自動で変換します
53 * @param score ライブで獲得したスコアを入力します
54 * @param room ルームアイテムによる補正値を百分率のまま(xxx%)入力します
55 * @param center センター、ゲスト効果による補正値を百分率のまま入力します
56 * @param produce プロデュース方針による補正値を百分率のまま入力します
57 * @param premium プレミアムパスによる補正値を百分率のまま入力します
59 * @return 一人あたりの獲得ファン数。1回のライブで獲得出来るファン数はこの値の5倍です
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)
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());
84 * 端数切り上げ(スコア*0.001*ルーム補正値*センター、ゲスト効果補正値*プロデュース方針補正値)
85 * ルーム、センター、ゲスト、プロデュース方針の補正値は百分率。計算時に自動で変換します
89 * @param center センターアイドル補正値
90 * @param produce プロデュース方針補正値
91 * @param premium プレミアムパス補正値
93 * @return 一人当たりの獲得ファン数がラップされているCompletableFuture
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);
101 * 初期実装の思想は並列処理による再帰計算。
104 * @param multiplier LIVEの繰り返し回数
105 * @param room ルームアイテム補正値(百分率)
106 * @param center センター、ゲスト効果による補正値
107 * @param produce プロデュース方針にとる補正値
108 * @param premium プレミアムパスによる補正値
110 * @return LIVE一回当たりの目標スコアがラップされているCompletableFuture
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);
118 * 初期実装の思想は並列処理による再帰計算。
121 * @param multiplier LIVEの繰り返し回数
122 * @param room ルームアイテム補正値(百分率)
123 * @param center センター、ゲスト効果による補正値
124 * @param produce プロデュース方針にとる補正値
125 * @param premium プレミアムパスによる補正値
127 * @return LIVE一回当たりの目標スコア
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.");
135 int localFan = fan(result.incrementAndGet(), room, center, produce, premium) * 5;
136 if(goalFan.compareTo(new BigDecimal(localFan)) <= 0) {
140 logger.info("Finished calculating. Estimated Fan value : {}", result.intValue());
141 return Integer.parseInt(result.toString());