parent
4199a269fd
commit
e889b75605
@ -0,0 +1,104 @@ |
|||||||
|
package me.lensferno.dogename.select; |
||||||
|
|
||||||
|
import javafx.animation.AnimationTimer; |
||||||
|
import javafx.beans.property.SimpleBooleanProperty; |
||||||
|
import javafx.beans.property.StringProperty; |
||||||
|
import javafx.beans.value.ChangeListener; |
||||||
|
import me.lensferno.dogename.configs.MainConfig; |
||||||
|
import me.lensferno.dogename.configs.VoiceConfig; |
||||||
|
import me.lensferno.dogename.data.History; |
||||||
|
import me.lensferno.dogename.data.NameData; |
||||||
|
import me.lensferno.dogename.select.core.Worker; |
||||||
|
import me.lensferno.dogename.voice.TokenManager; |
||||||
|
import me.lensferno.dogename.voice.VoicePlayer; |
||||||
|
|
||||||
|
public final class Selector { |
||||||
|
|
||||||
|
Processor processor = new Processor(); |
||||||
|
|
||||||
|
private VoicePlayer voicePlayer = null; |
||||||
|
|
||||||
|
public Selector() { |
||||||
|
initialVoicePlayer(); |
||||||
|
} |
||||||
|
|
||||||
|
public void initialVoicePlayer() { |
||||||
|
TokenManager tokenManager = new TokenManager(); |
||||||
|
VoiceConfig voiceConfig = new VoiceConfig(); |
||||||
|
tokenManager.init(); |
||||||
|
if (tokenManager.getTokenStatus() == TokenManager.TOKEN_OK) { |
||||||
|
voicePlayer = new VoicePlayer(tokenManager.getToken(), voiceConfig); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void run() { |
||||||
|
processor.setNumberRange(); |
||||||
|
processor.updateNewValue(); |
||||||
|
processor.stoppedIndicatorProperty().set(false); |
||||||
|
|
||||||
|
processor.start(); |
||||||
|
} |
||||||
|
|
||||||
|
public void forceStop() { |
||||||
|
processor.stopProcess(); |
||||||
|
} |
||||||
|
|
||||||
|
public void initialVariable(MainConfig config, NameData nameData, History history, StringProperty... labelTexts) { |
||||||
|
processor.initialVariable(config, voicePlayer, nameData, history, labelTexts); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isWorkerRunning() { |
||||||
|
return processor.isWorkerRunning(); |
||||||
|
} |
||||||
|
|
||||||
|
public void addStoppedEventListener(ChangeListener<? super Boolean> listener) { |
||||||
|
processor.stoppedIndicatorProperty().addListener(listener); |
||||||
|
} |
||||||
|
|
||||||
|
// ---------------------------------------------------
|
||||||
|
static class Processor extends AnimationTimer { |
||||||
|
|
||||||
|
private Worker coreWorker; |
||||||
|
|
||||||
|
MainConfig config = null; |
||||||
|
|
||||||
|
protected void initialVariable(MainConfig config, VoicePlayer voicePlayer, NameData nameData, History history, StringProperty... labelTexts) { |
||||||
|
coreWorker = new Worker(labelTexts, config, nameData, history, voicePlayer); |
||||||
|
this.config = config; |
||||||
|
} |
||||||
|
|
||||||
|
protected void updateNewValue() { |
||||||
|
coreWorker.setSpeed(100 - config.getSpeed()); |
||||||
|
coreWorker.setMaxTotalCount(config.getMaxTotalCount()); |
||||||
|
} |
||||||
|
|
||||||
|
protected SimpleBooleanProperty stoppedIndicatorProperty() { |
||||||
|
return coreWorker.stoppedIndicatorProperty(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void handle(long time) { |
||||||
|
coreWorker.displaySelectedResult(); |
||||||
|
if (coreWorker.getStoppedIndicator()) { |
||||||
|
this.stop(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void stopProcess() { |
||||||
|
coreWorker.setForceStop(true); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isWorkerRunning() { |
||||||
|
return !coreWorker.getStoppedIndicator(); |
||||||
|
} |
||||||
|
|
||||||
|
public void setNumberRange() { |
||||||
|
int minNumber = Integer.parseInt(config.getMinNumber()); |
||||||
|
int maxNumber = Integer.parseInt(config.getMaxNumber()); |
||||||
|
coreWorker.setNumberRange(minNumber, maxNumber); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
@ -0,0 +1,203 @@ |
|||||||
|
package me.lensferno.dogename.select.core; |
||||||
|
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty; |
||||||
|
import javafx.beans.property.StringProperty; |
||||||
|
import me.lensferno.dogename.configs.MainConfig; |
||||||
|
import me.lensferno.dogename.data.History; |
||||||
|
import me.lensferno.dogename.data.NameData; |
||||||
|
|
||||||
|
import me.lensferno.dogename.utils.Random; |
||||||
|
import me.lensferno.dogename.voice.VoicePlayer; |
||||||
|
|
||||||
|
public final class Worker { |
||||||
|
|
||||||
|
private final Random randomNumber = new Random(); |
||||||
|
|
||||||
|
private final StringProperty[] labelTexts; |
||||||
|
private final SimpleBooleanProperty stoppedIndicator = new SimpleBooleanProperty(true); |
||||||
|
|
||||||
|
private final MainConfig config; |
||||||
|
|
||||||
|
//挑选方法
|
||||||
|
private final int selectMethod = MainConfig.METHOD_NAME; |
||||||
|
private final NameData nameData; |
||||||
|
|
||||||
|
private final History history; |
||||||
|
|
||||||
|
private final VoicePlayer voicePlayer; |
||||||
|
|
||||||
|
private int speed = 0; |
||||||
|
|
||||||
|
//数值范围最大最小值
|
||||||
|
private final int[] numberRange = new int[2]; |
||||||
|
private final int MIN_NUMBER = 0; |
||||||
|
private final int MAX_NUMBER = 1; |
||||||
|
|
||||||
|
//挑选次数和每一轮的挑选次数
|
||||||
|
private int maxTotalCount = MainConfig.DEFAULT_MAX_TOTAL_COUNT; |
||||||
|
private int maxCycleCount = 0; |
||||||
|
|
||||||
|
//已经挑选了多少次
|
||||||
|
private int totalCount = 0; |
||||||
|
private int cycleCount = 0; |
||||||
|
|
||||||
|
private boolean finalResult = true; |
||||||
|
|
||||||
|
private boolean forceStop = false; |
||||||
|
|
||||||
|
private String selectedResult; |
||||||
|
private boolean continueSelecting = false; |
||||||
|
|
||||||
|
private int resultLabelId = 0; |
||||||
|
|
||||||
|
private final Counter counter = new Counter(); |
||||||
|
|
||||||
|
public Worker(StringProperty[] labelTexts, MainConfig config, NameData nameData, History history, VoicePlayer voicePlayer) { |
||||||
|
this.labelTexts = labelTexts; |
||||||
|
this.config = config; |
||||||
|
this.nameData = nameData; |
||||||
|
this.history = history; |
||||||
|
this.voicePlayer = voicePlayer; |
||||||
|
} |
||||||
|
|
||||||
|
private void select() { |
||||||
|
// try的位置待定(前面or后面)
|
||||||
|
// 延时用,用于调整挑选速度
|
||||||
|
try { |
||||||
|
Thread.sleep(speed); |
||||||
|
} catch (Exception e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
|
||||||
|
stoppedIndicator.set(false); |
||||||
|
|
||||||
|
// 若 计数已达最大总数(挑选次数)或强制停止,进入停止分支,
|
||||||
|
if (totalCount >= maxTotalCount || forceStop) { |
||||||
|
// 任意三种情况就停止:已忽略名单中没有该名字;不考虑忽略名单;强制停止
|
||||||
|
// 如果不是这三种情况就选到符合其中一种情况为止
|
||||||
|
// 由于后两者在安排进程中不可能改变,因此继续挑选后只有选中的结果不在忽略名单中才会结束挑选
|
||||||
|
// 若忽略名单已满(名单中数量=总的名单数量),点击“安排一下”时会提示已满,无法再进行挑选,因此在运行时总有 忽略名单<总名单,总有名字不在忽略列表中,不会死循环,放心吧
|
||||||
|
boolean resultIgnored = (config.getChooseMethod() == MainConfig.METHOD_NAME) ? (nameData.getIgnoreNameList().contains(selectedResult)) : (nameData.getIgnoreNumberList().contains(selectedResult)); |
||||||
|
if (!resultIgnored || !config.getPassSelectedResult() || forceStop) { |
||||||
|
this.stopSelect(); |
||||||
|
finalResult = true; |
||||||
|
return; |
||||||
|
} else { |
||||||
|
continueSelecting = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
counter.count(); |
||||||
|
resultLabelId = counter.getNewResultLabelId(); |
||||||
|
finalResult = false; |
||||||
|
|
||||||
|
this.selectedResult = this.pick(config.getChooseMethod()); |
||||||
|
} |
||||||
|
|
||||||
|
public void stopSelect() { |
||||||
|
if (config.getPassSelectedResult()) { |
||||||
|
nameData.getIgnoreNameList().add(selectedResult); |
||||||
|
} |
||||||
|
|
||||||
|
if (config.getEqualMode()) { |
||||||
|
nameData.writeIgnoreList(NameData.NAME_ONLY); |
||||||
|
} |
||||||
|
|
||||||
|
history.addHistory(selectedResult); |
||||||
|
|
||||||
|
if (config.getVoicePlay() && voicePlayer != null) { |
||||||
|
voicePlayer.playVoice(selectedResult); |
||||||
|
} |
||||||
|
|
||||||
|
counter.resetCounter(); |
||||||
|
stoppedIndicator.set(true); |
||||||
|
forceStop = false; |
||||||
|
System.gc(); |
||||||
|
} |
||||||
|
|
||||||
|
private String pick(int selectMethod) { |
||||||
|
switch (selectMethod) { |
||||||
|
case MainConfig.METHOD_NAME: |
||||||
|
return nameData.randomGet(config.getSecureRandom()); |
||||||
|
case MainConfig.METHOD_NUMBER: |
||||||
|
randomNumber.setUseSecureRandom(config.getSecureRandom()); |
||||||
|
return String.valueOf(randomNumber.getRandomNumber(numberRange[MIN_NUMBER], numberRange[MAX_NUMBER])); |
||||||
|
default: |
||||||
|
return "(´・ω・`)?"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void displaySelectedResult() { |
||||||
|
this.select(); |
||||||
|
|
||||||
|
if (!finalResult) { |
||||||
|
labelTexts[resultLabelId].set(selectedResult); |
||||||
|
} else { |
||||||
|
for (StringProperty labelText : labelTexts) { |
||||||
|
if (labelText.get().contains("→")) { |
||||||
|
labelText.set(labelText.get().replace("→", "").replace("←", "")); |
||||||
|
} |
||||||
|
} |
||||||
|
labelTexts[resultLabelId].set(String.format("→%s←", selectedResult)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 这里有个内部类Counter计数菌
|
||||||
|
final class Counter { |
||||||
|
|
||||||
|
private int newResultLabelId = 0; |
||||||
|
|
||||||
|
protected void count() { |
||||||
|
newResultLabelId = resultLabelId; |
||||||
|
|
||||||
|
// 每一轮的计数到达最大时并且不强制继续这轮挑选时,重置这一轮的挑选,并指派新的显示label
|
||||||
|
// 否则这一轮的计数直接+1
|
||||||
|
if (cycleCount >= maxCycleCount && !continueSelecting) { |
||||||
|
cycleCount = 0; |
||||||
|
maxCycleCount = randomNumber.getRandomNumber(1, maxTotalCount - totalCount); |
||||||
|
newResultLabelId = randomNumber.getRandomNumber(labelTexts.length - 1); |
||||||
|
} else { |
||||||
|
cycleCount++; |
||||||
|
} |
||||||
|
|
||||||
|
totalCount++; |
||||||
|
} |
||||||
|
|
||||||
|
protected void resetCounter() { |
||||||
|
totalCount = 0; |
||||||
|
cycleCount = 0; |
||||||
|
maxCycleCount = 0; |
||||||
|
|
||||||
|
continueSelecting = false; |
||||||
|
} |
||||||
|
|
||||||
|
protected int getNewResultLabelId() { |
||||||
|
return newResultLabelId; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public boolean getStoppedIndicator() { |
||||||
|
return stoppedIndicator.get(); |
||||||
|
} |
||||||
|
|
||||||
|
public SimpleBooleanProperty stoppedIndicatorProperty() { |
||||||
|
return stoppedIndicator; |
||||||
|
} |
||||||
|
|
||||||
|
public void setNumberRange(int minNumber, int maxNumber) { |
||||||
|
this.numberRange[MIN_NUMBER] = minNumber; |
||||||
|
this.numberRange[MAX_NUMBER] = maxNumber; |
||||||
|
} |
||||||
|
|
||||||
|
public void setForceStop(boolean forceStop) { |
||||||
|
this.forceStop = forceStop; |
||||||
|
} |
||||||
|
|
||||||
|
public void setMaxTotalCount(int maxTotalCount) { |
||||||
|
this.maxTotalCount = maxTotalCount; |
||||||
|
} |
||||||
|
|
||||||
|
public void setSpeed(int speed) { |
||||||
|
this.speed = speed; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
package me.lensferno.dogename.utils; |
||||||
|
|
||||||
|
import java.security.SecureRandom; |
||||||
|
|
||||||
|
public final class Random { |
||||||
|
|
||||||
|
private final java.util.Random random = new java.util.Random(); |
||||||
|
private final java.util.Random secRandom = new SecureRandom(); |
||||||
|
|
||||||
|
private boolean useSecureRandom = true; |
||||||
|
|
||||||
|
public void setUseSecureRandom(boolean useSecureRandom) { |
||||||
|
this.useSecureRandom = useSecureRandom; |
||||||
|
} |
||||||
|
|
||||||
|
public int getRandomNumber (int minNumber, int maxNumber) { |
||||||
|
if (useSecureRandom){ |
||||||
|
return minNumber + secRandom.nextInt(maxNumber - minNumber + 1); |
||||||
|
} else { |
||||||
|
return minNumber + random.nextInt(maxNumber - minNumber + 1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public int getRandomNumber (int maxNumber) { |
||||||
|
if (useSecureRandom){ |
||||||
|
return secRandom.nextInt(maxNumber + 1); |
||||||
|
} else { |
||||||
|
return random.nextInt(maxNumber + 1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue