Skip to content

Instantly share code, notes, and snippets.

@tateisu
Created May 6, 2020 08:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tateisu/e2730cdb7f8513418c23cf18173cb96f to your computer and use it in GitHub Desktop.
Save tateisu/e2730cdb7f8513418c23cf18173cb96f to your computer and use it in GitHub Desktop.
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