MLTD 9th 周年イベント オプティマイザー

アイドルマスターミリオンライブ!シアターデイズ周年イベント(9th)の効率的なプレイ計画を算出します。

このページはアルゴリズムの概要を説明したものです。厳密な挙動や細かい数値については、ソースコードを直接参照してください。

用語定義

ルーティン

お仕事でチケットを1800枚収集し、続けて通常曲をライブ4回プレイするひとまとまりの行動です。どの曲を選ぶかによって2種類あります。

問題設定

イベント期間と構成

イベントは1〜13日目の全13日間です。1〜6日目が前半戦、7〜13日目が後半戦となります。(以下のアルゴリズム説明では、実装の配列添字に合わせて0-indexで表記します。)

決定変数

各 day d について、以下の2つを決定します。

固定行動(毎日必ず行う)

上記の固定行動(およびログイントリガーの受け取り)は、シミュレーション開始日より後の日では毎日必ず行います。開始日についてのみ、設定で「既に済ませた」とした要素は改めて行いません。除外される収支・所要時間の詳細は後述の「1日の固定収支」の「開始日で済ませた要素がある場合」を参照してください。

制約条件

トリガーとポイントの収支

1日の固定収支(ログイン・おすすめ楽曲・周年10倍・ブースト)

下式は、ログイントリガー未取得・ミッショントリガー(おすすめ楽曲ミッション)未取得・ブースト未使用・周年曲10倍未プレイという初期状態を前提とした、ある1日の固定収支です。シミュレーション開始日より後の日はすべてこの前提で計算します。開始日についてのみ、設定でこれらを「済ませた」とした場合に、下の「開始日で済ませた要素がある場合」のとおり変化します。

固定トリガー獲得 =
  ログインボーナス (540)
  + おすすめ楽曲ミッション (1000 × 4 = 4000)
  + おすすめ楽曲ルーティン (1071 × 4 = 4284)
  [+ 通常曲ブースト時:追加ルーティン分 (4284 × 追加ルーティン回数) + 450枚ライブ10回分のボーナス (1071 × 10)]

固定トリガー消費 =
  周年曲10倍ライブ (1800 × 1 [前半] または1800 × 2 [後半])
  [+ 周年曲ブースト時:4倍ライブ10回分 (720 × 10 = 7200)]

固定ポイント獲得 =
  おすすめ楽曲ルーティン (1071 × 4 = 4284)
  + 周年曲10倍ライブ (537 × 10 × 1 [前半] または537 × 10 × 2 [後半])
  [+ 通常曲ブースト時:追加ルーティン分 (4284 × 追加ルーティン回数) + 450枚ライブ10回分のボーナス (1071 × 10)]
  [+ 周年曲ブースト時:4倍ライブ10回分・2倍ボーナス (537 × 4 × 2 × 10 = 42960)]

開始日で済ませた要素がある場合:シミュレーション開始日について、設定で「既に済ませた」とした要素の成果は「現在の所持ポイント/トリガー」に含まれているものとして扱い、上記の固定収支から除きます。各要素の変化は次のとおりです。

追加行動による収支

追加ルーティン1回あたり:
  トリガー獲得 +4284、ポイント獲得 +4284

追加周年曲4倍ライブ1回あたり:
  トリガー消費 −720、ポイント獲得 +2148

確定モードの最適化アルゴリズム

概要:2段階の貪欲法

おすすめ楽曲スケジュールが全日確定している場合に用います。各日の追加ルーティン回数と追加4倍ライブ回数を、以下の2つの段階に分けて決定します。

第1段階:追加ルーティン回数の決定

各日の「ルーティン1回あたりの所要時間」(お仕事時間 + ライブ4回分 + 遷移時間)を計算し、その所要時間が短い日から順に各日の追加ルーティン回数を決めます。この段階では4倍ライブの回数は決めません。

ルーティン所要時間が短い日ほど、時間あたりのトリガー・ポイント獲得量が大きくなります。そのため、短い順に決めることで効率の良い計画を立てます。一方、4倍ライブは「前の日に集めたトリガーを後の日で使う」という時系列の依存があるため、第2段階で day 0 から順に処理します。

day d の追加ルーティン回数 r[d] は、0回を下限として以下の上限のもとで選ばれます。

上記の上限のもとで、「将来トリガーが溢れない範囲での最大の回数」を選択します。周年曲ブーストなどの固定消費を賄うために最低限必要なルーティンは、第2段階で過去日へ補填します(下記参照)。

第2段階:追加4倍ライブ回数の決定と空き時間の充填

各日のルーティン回数が確定したあと、day 0 から時系列順に各日を処理します。各日の処理は以下の順で行います。

1. 固定消費を賄う最低ルーティンの補填

周年曲ブーストなど、その day d の固定行動に必要なトリガー消費を、その時点までの累積トリガー残高で賄えない場合があります。その不足分(必要回数 = ceil(不足トリガー / 4284))を満たすまで、シミュレーション開始日〜当日(SIMULATE_START_DAY〜day d)のうちそのルーティンを追加しても稼働超過が最も小さくなる日を1回ずつ選んでルーティンを追加します。この補填は固定行動を成立させるためのものであり、時間上限の超過を許容します(時間制約の例外)。

2. 4倍ライブの決定

固定行動と第1段階で決めたルーティンを反映したうえで、残り時間とトリガー残高の範囲で追加の4倍ライブを行います。

再演1回分の時間 = 周年曲の曲時間 + 曲終了→次曲開始(再演)の時間
追加4倍ライブの最初の1回に必要な時間 = メニュー遷移 + 楽曲選択画面→曲開始 + 周年曲の曲時間 + 曲終了→楽曲選択画面

時間で可能な回数 =
  1 + floor((残り時間 − 追加4倍ライブの最初の1回に必要な時間) / 再演1回分の時間)

追加4倍ライブ回数 =
  min(
    max(0, 時間で可能な回数),
    floor(その日終了時点のトリガー残高 / 720)
  )

追加4倍ライブは、初回から再演までをまとめた1つの4倍ブロックとして扱います。最初の1回にはメニュー遷移・曲開始前・曲終了後の時間を含め、2回目以降は再演1回分の時間だけで数えます。「その日終了時点のトリガー残高」は、開始日からその day d までの累積獲得から累積消費を引いた、その日の終了時点で実際に手元にあるトリガー量です。各日はこの残高の範囲でのみ4倍ライブを撃ちます。

3. 空き時間の充填

4倍ライブを決定したあと、残り時間がその日のルーティン1回分以上残っている場合は、「ルーティンを1回追加し、続けて上の手順で4倍ライブを追加する」操作を残り時間が尽きるまで繰り返します。トリガー切れで時間が余っている日の空き時間を、この充填で埋めます。

未確定モードのアルゴリズム

概要:モンテカルロシミュレーション

シミュレーション開始日(以下「開始日」)より後の日のおすすめ楽曲スケジュールが未定の場合に用います。未来の曲割り当てをランダムに試行し、最終的な獲得ポイントが最大となるような開始日の追加ルーティン回数を推定します。実装の単純化・高速化のために、開始日より後ろの日は既知と仮定してシミュレーションしているため、厳密な期待値とは異なります。

手順

  1. 開始日の追加ルーティン回数の候補を列挙する。下限は、開始日の固定行動のトリガー消費(周年曲ブーストおよび周年曲最低時間による追加4倍ライブ分を含む)を賄うために最低限必要なルーティン回数。上限は、稼働可能時間内でプレイできる回数とこの下限のうち大きい方(固定行動を成立させるためのルーティンは稼働超過を許容するため)。
  2. 各候補について、既定の回数(50回)のシミュレーションを実行する。
    • 開始日の翌日以降の未割り当てアイドルをランダムに並べ替える。
    • その並び順でおすすめ楽曲スケジュールを埋め、確定モードと同じアルゴリズムで解を求め、最終ポイントを記録する。
  3. 各候補ごとに、合計最終ポイントを試行回数で平均して、その候補の最終ポイントの期待値を計算する。
  4. 最終ポイントの期待値が最大となる追加ルーティン回数を開始日の推奨値として採用する。
出力されるのは開始日の推奨行動のみです。 2日目以降の各日の行動内訳は、実際の曲割り当てが確定してから改めて計算してください。

時間最小化モード

概要:二分探索

「目標ポイントを達成するための最小稼働時間」を求めるモードです。全日の稼働可能時間に均一に乗じる倍率 m(0〜1)を二分探索で求め、そのときの計画を出力します。

二分探索の手順

  1. 倍率 m = 1(フルタイム)で最適化した場合のポイントが目標以上かを確認する。達成できなければ「目標未達」として終了する。
  2. lo = 0, hi = 1 として倍率を17回の二分探索で絞り込む。
  3. 各イテレーションで scaled[d] = trunc(canRunTime[d] × m) として最適化を実行する。目標ポイントを達成できれば hi = m、できなければ lo = m とする。
  4. 最終的に hi 側の計画を出力する。
稼働時間は整数秒に丸めて使用します。最大稼働秒数は86400秒(24時間)であり、log₂(86400) ≈ 16.4から、 17回の二分探索でほぼ秒単位の精度に収束します。倍率はすべての日に均一に乗じるため、「特定の日だけ短縮する」「全体の合計の稼働時間最小化」といった最適化には対応していません。

時間計算の詳細

おすすめ楽曲1周の所要時間

おすすめ楽曲1周 =
  (メニュー遷移時間 + お仕事時間)
  + メニュー遷移時間
  + (楽曲選択画面→曲開始 +  曲終了→楽曲選択画面) × 4曲
  + おすすめ楽曲の曲時間の合計

おすすめ楽曲はそれぞれ異なるため再演が行えません。楽曲選択画面→曲開始の時間, 曲終了→楽曲選択画面の時間 は各曲ごとにかかります。

追加ルーティン1回の所要時間

追加ルーティン1回 =
  (メニュー遷移時間 + お仕事時間)
  + メニュー遷移時間
  + 楽曲選択画面→曲開始
  + おすすめ楽曲の中で最短曲の曲時間 × 4
  + 曲終了→次曲開始(再演) × 3
  + 曲終了→楽曲選択画面

追加ルーティンでは4回のライブすべてで同じ曲をプレイできるため、その日のおすすめ楽曲4曲のうち最も短い曲の時間を使います。再演可能であるため、楽曲選択画面→曲開始の時間は1回のみかかります。

周年曲の所要時間

周年曲(N曲) =
  メニュー遷移時間
  + 楽曲選択画面→曲開始
  + 周年曲時間 × N
  + 曲終了→次曲開始(再演) × (N − 1)
  + 曲終了→楽曲選択画面

再演可能であるため、楽曲選択画面→曲開始の時間 は1回のみかかります。

必要ジュエルの計算

全期間の消費スタミナから、スパークドリンクによる回復量を差し引いた不足分を、ジュエルによるスタミナ回復(1回 = 最大スタミナ分回復、50ジュエル)で賄う想定で計算します。プロデューサーレベルアップによるスタミナ回復・スタミナ最大量の増加は考慮していません。つまり、必要なジュエル数の上界をざっくり計算しています。

消費スタミナ合計 = Σ(全日) [ルーティン回数 × 1800]

ドリンク回復量 =
  ドリンク10 個数 × 10
  + ドリンク20 個数 × 20
  + ドリンク30 個数 × 30
  + ドリンクMAX 個数 × 最大スタミナ

不足スタミナ = max(0, 消費スタミナ合計 − ドリンク回復量)
回復回数 = ceil(不足スタミナ / 最大スタミナ)
必要ジュエル = 回復回数 × 50

参考

制作するにあたり参考にしたページです。