Created
May 6, 2020 08:23
-
-
Save tateisu/e2730cdb7f8513418c23cf18173cb96f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public delegate Boolean WhenCondition(CanStartRoom arg); | |
public delegate Int64 WhenAction(CanStartRoom arg); | |
public delegate void WhenPre(CanStartRoom arg); | |
public class WhenNode { | |
public String? situation; | |
public WhenCondition condition; | |
public WhenAction action; | |
public WhenPre? preAction; | |
public Boolean isElse; | |
public WhenNode(String? situation, WhenCondition c, WhenAction a, WhenPre? preAction = null, Boolean isElse = false) { | |
this.condition = c; | |
this.action = a; | |
this.situation = situation; | |
this.preAction = preAction; | |
this.isElse = isElse; | |
} | |
} | |
public class When { | |
private readonly WhenPre? preAction; | |
private readonly WhenNode[] cases; | |
public When(WhenPre? preAction, params WhenNode[] cases) { | |
this.preAction = preAction; | |
this.cases = cases; | |
var size = cases.Length; | |
if (size == 0) | |
throw new ArgumentException( "missing cases" ); | |
for (var i = 0; i < size; ++i) { | |
if (cases[ i ].isElse != ( i == size - 1 )) | |
throw new ArgumentException( "incorrect else state." ); | |
} | |
} | |
public When(params WhenNode[] cases) : this( null, cases ) { } | |
public Int64 eval(CanStartRoom arg) { | |
preAction?.Invoke( arg ); | |
foreach (var node in cases) { | |
if (node.condition.Invoke( arg )) { | |
if (node.situation != null) | |
arg.situation = node.situation; | |
node.preAction?.Invoke( arg ); | |
return node.action.Invoke( arg ); | |
} | |
} | |
throw new NotSupportedException( "どの条件にも一致しなかった" ); | |
} | |
} | |
public static WhenNode whenCase(WhenCondition condition, String? situation, WhenAction action, WhenPre? preAction = null) => new WhenNode( situation, condition, action, preAction ); | |
public static WhenNode whenCase(WhenCondition condition, WhenAction action, WhenPre? preAction = null) => new WhenNode( null, condition, action, preAction ); | |
public static WhenNode whenElse(String? situation, WhenAction action, WhenPre? preAction = null) => new WhenNode( situation, (_) => true, action, preAction, isElse: true ); | |
public static WhenNode whenElse(WhenAction action, WhenPre? preAction = null) => new WhenNode( null, (_) => true, action, preAction, isElse: true ); | |
public static WhenAction nestWhen(params WhenNode[] cases) { | |
var when = new When( cases ); | |
return (CanStartRoom self) => when.eval( self ); | |
} | |
private static WhenAction dontOpenAction(Func<CanStartRoom, String> reasonFunc, Func<CanStartRoom, Int64?>? remainFunc = null) | |
=> (CanStartRoom self) => self.dontOpen( reasonFunc( self ), remainFunc?.Invoke( self ) ); | |
private static WhenAction willOpenAction(Func<CanStartRoom, String> reasonFunc) | |
=> (CanStartRoom self) => self.willOpen( reasonFunc( self ) ); | |
private static WhenAction forceOpenAction(Func<CanStartRoom, String> msgFunc) | |
=> (CanStartRoom self) => self.forceOpen( msgFunc( self ) ); | |
private static WhenAction investigateOnlyAction | |
(Func<CanStartRoom, String> lineFunc, Func<CanStartRoom, Int64> remainFunc) | |
=> (CanStartRoom self) => self.investigateOnly( lineFunc( self ), remainFunc( self ) ); | |
private static WhenAction normalGetAction( | |
Func<CanStartRoom, String> waitCaptionFunc, | |
Func<CanStartRoom, Int32?>? maxGiftCountFunc = null, | |
Func<CanStartRoom, Int64?>? waitDurationFunc = null, | |
Func<CanStartRoom, String?>? preferGetFirstReasonFunc = null, | |
Func<CanStartRoom, String?>? dontGetFirstReasonFunc = null, | |
Func<CanStartRoom, Boolean?>? dontGetFirstIfGiftCountEnoughFunc = null | |
) | |
=> (self) => self.normalGet( | |
waitCaptionFunc.Invoke( self ), | |
maxGiftCountFunc?.Invoke( self ), | |
waitDurationFunc?.Invoke( self ), | |
preferGetFirstReasonFunc?.Invoke( self ), | |
dontGetFirstReasonFunc?.Invoke( self ), | |
dontGetFirstIfGiftCountEnoughFunc?.Invoke( self ) | |
); | |
private static readonly When checkData = new When( | |
// 部屋一覧に情報がない | |
whenCase( | |
(self) => !self.checkClosing && ( self.rooms?.Count ?? 0 ) == 0, | |
"情報不足", | |
dontOpenAction( (_) => "オンライブ部屋一覧がありません", (_) => UnixTime.minute1 * 3 ) | |
), | |
// 強制的に開くがON | |
whenCase( | |
(self) => self.garner.forceOpenReason != null, | |
"強制的に開く", | |
willOpenAction( (self) => self.garner.forceOpenReason ?? "?" ) | |
), | |
// 解除制限 | |
whenCase( | |
(self) => self.remainExpireExceed >= Config.waitBeforeGift, | |
"制限エラー", | |
preAction: (self) => self.garner.overrun = false, | |
action: dontOpenAction( (_) => "今は取得できません", (self) => self.remainExpireExceed ) | |
), | |
// 取得制限まで取る | |
whenCase( | |
(self) => self.garner.overrun, | |
"取得制限まで取る", | |
willOpenAction( (_) => "エラーが出るまで取得します。" ) | |
), | |
// 時間内に10回取得してるなら調査だけ | |
whenCase( | |
(self) => self.remainExpectedReset >= Config.waitBeforeGift && self.historyCount >= 10, | |
"10回取得済み", | |
investigateOnlyAction( (_) => $"解除予測まで待機します", (self) => self.remainExpectedReset ) | |
), | |
// 配信予定なし | |
whenCase( | |
(self) => self.st == null, | |
"配信予定なし", | |
action: normalGetAction( (_) => "適当に待機します" ) | |
), | |
// 配信開始後(3周目以降) | |
whenCase( | |
(self) => self.remainThirdLap < Config.waitBeforeGift, | |
"3周目後", | |
preAction: (self) => { | |
if (self.garner.willPlayThirdLap( self.st!.time )) | |
self.window.notificationSound.play( NotificationSound.thirdLap ); | |
}, | |
action: normalGetAction( | |
(_) => "適当に待機します", | |
preferGetFirstReasonFunc: (self) => self.thirdLapPreferReason() | |
) | |
), | |
// 配信開始後(3周目より前) | |
// 配信開始が実際には遅れるかもしれない | |
// 「450未満なら取得」で良いと思う。投げてなければ取得しないのだし | |
whenCase( | |
(self) => self.remainLiveStart < Config.waitBeforeGift, | |
"配信開始後", | |
preAction: (self) => { | |
if (self.garner.willPlayLiveStart( self.st!.time )) | |
self.window.notificationSound.play( NotificationSound.liveStart ); | |
}, | |
action: normalGetAction( (_) => "適当に待機します" ) | |
), | |
// 捨て星以降 | |
whenCase( | |
(self) => self.remainDropGift < Config.waitBeforeGift, | |
"捨て星以降", | |
nestWhen( | |
whenCase( | |
(self) => !self.hasResetTime, | |
nestWhen( | |
whenCase( | |
(self) => self.remainThirdLap - Config.waitBeforeGift >= UnixTime.minute1 * 57, | |
"配信前(初回取得済前,3周目まで57分以上)", | |
willOpenAction( (_) => "捨て星します" ) | |
), | |
// いま50とっても5無駄になる | |
whenCase( | |
(self) => self.sumGiftCount >= 450, | |
"配信前(初回取得済前,タイミング悪,450所持)", | |
investigateOnlyAction( | |
(_) => "初回取得しません", | |
remainFunc: (self) => self.remainLiveStart | |
) | |
), | |
// 捨て星タイミングが合わないしギフト所持数も揃わないので、諦めて取れるだけ取る | |
whenElse( | |
"配信前(初回取得済前,タイミング悪,所持数不足)", | |
willOpenAction( (_) => "タイミング調整を諦めて初回を取ります" ) | |
) | |
) | |
), | |
whenElse( | |
nestWhen( | |
// 配信開始より後に解除予測がある | |
whenCase( | |
(self) => self.remainLiveStart < self.remainExpectedReset, | |
"配信前(取得1回以上,解除予測<配信開始)", | |
normalGetAction( (_) => "配信開始まで待機します" ) | |
), | |
// 配信開始より後に解除予測がある | |
// 495まで取る。解除予測が来ても初回を取らない場合などに有効 | |
whenElse( | |
"配信前(取得1回以上,解除予測>=配信開始)", | |
normalGetAction( | |
(_) => "解除予測まで待機します", | |
waitDurationFunc: (self) => self.remainExpectedReset, | |
maxGiftCountFunc: (self) => 495 | |
) | |
) | |
) | |
) | |
) | |
), | |
// 捨て星前1時間以内 | |
whenCase( | |
(self) => self.remainDropGift < Config.waitBeforeGift - UnixTime.hour1 && self.hasResetTime, | |
"捨て星1時間以内(初回取得後)", | |
normalGetAction( (_) => "捨て星まで待機します", waitDurationFunc: (self) => self.remainDropGift ) | |
), | |
// 捨て星前1時間以内 | |
whenCase( | |
(self) => self.remainDropGift < Config.waitBeforeGift - UnixTime.hour1, | |
"捨て星1時間以内(初回取得前)", | |
nestWhen( | |
whenCase( (self) => self.timingDelta > 0L, dontOpenAction( (_) => "初回取得のタイミングを待ちます", remainFunc: (self) => self.remainDropGift ) ), | |
whenCase( (self) => self.timingDelta >= UnixTime.minute1 * -3, forceOpenAction( (_) => "タイミングが良いので初回を取りたい" ) ), | |
whenCase( (self) => self.sumGiftCount >= 450, dontOpenAction( (self) => $"所持数450以上なので初回取得を避けます", remainFunc: (self) => self.remainDropGift ) ), | |
whenElse( forceOpenAction( (_) => "タイミングを逃したが、所持数が少ないので初回取得する" ) ) | |
) | |
), | |
// 捨て星前1時間以上 | |
whenElse( | |
preAction: (self) => { | |
var n = ( self.remainDropGift - Config.waitBeforeGift ) / UnixTime.hour1; | |
self.situation = $"捨て星前{n}時間以上"; | |
}, | |
action: normalGetAction( (_) => "捨て星まで待機します", waitDurationFunc: (self) => self.remainDropGift ) | |
) | |
); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment