Attempts to find the optimal commander battle order for union raids. Originally made for the Pockult union.
Assumptions:
- The amount of damage dealt by each commander is known for each boss and at each level
- No variance term is modeled in the damage dealt by each commander (i.e. not performing a Monte Carlo simulation and displaying the statistics)
- The amount of health per boss is known at every level
- Only one day of raids are being considered. A user would have to update the boss health for day N using the results from day N-1 and run the solver again.
- Uses the CP-SAT solver in the OR-Tools library (https://developers.google.com/optimization)
- Constraints:
- Each commander can only be used N times (user set parameter in the dashboard), but a commander can be used more than once at a boss
- A boss must be defeated before the next boss can be attacked
- All bosses at a level must be defeated before the next level can be started
- Objective:
- Maximize the number of bosses defeated and the amount of damage dealt to the last un-defeated boss
- Maximizing the total damage dealt to all bosses seems to be a harder problem for the solver (numerics?)
- Rounding all damage to the nearest 100K or 1M might help the solver but would require some refactoring
- CP-SAT will utilize all available CPU cores on the machine! Can wind up acting as a CPU stress test.
OR
- Install all Python dependencies
pip install -r requirements.txt
- Run the dashboard
streamlit run src/dashboard.py
- OR use a different port other than the default 8501
streamlit run src/dashboard.py --server.port <port>
- Open up the dashboard in your browser if it doesn't open automatically
http://localhost:<port>
- Set the number of times each commander can be used
- Set the time limit for the solver to run
- Give the CSV with the damage dealt by each commander to each boss
- Give the CSV with the health of each boss at each level
- Click the "Run Solver" button
- The solver will run for the specified time limit and display the results Results include a interactive bar chart, a printout of the battle order, and a table of the solution output.
- Sample CSVs are provided in the
assets
folder so the user can see the expected data formatpython src/synthetic_commander_damage_data.py
will generate a sample CSV with random damage (using an upper to lower bound) dealt by each commander to each boss that is linearly decreasing from boss level 1 to 10 and from commander 1 to 32.
- Estimating how much damage each commander deals to each boss likely has a high variance, and is possibly multi-modal given the game mechanics. This is the major limiting factor on the usability of the solver's output.
- Solver may not find an optimal solution if the time limit is too short, or if the raid setup presents a very challenging problem. Dramatically increasing the time limit may not significantly increase the number of bosses defeated. A few minutes seems to be a good rule of thumb.
- Could not get a Windows installer (https://github.com/takluyver/pynsist) built using Pynsist to work. The installer would run, but the Streamlit dashboard would not load. Their example streamlit app worked fine, so it might be due to the later version of Streamlit used in this project or the use of OR-Tools.
- Pyinstaller does not work in a straightforward manner with Streamlit, so a portable executable was not built.