Created
October 30, 2018 14:21
-
-
Save YSRKEN/f9dd803ad02a5cfe5e99a51221e20bb5 to your computer and use it in GitHub Desktop.
少女前線(ドルフロ)の遠征を最適化するやつ(Pythonとpulpを使用)
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
# coding: UTF-8 | |
import math | |
import pandas | |
import pulp | |
# 必要な資材量 | |
want_supply = { | |
'人力': 10000, | |
'弾薬': 22000, | |
'配給': 0, | |
'パーツ': 0 | |
} | |
# 遠征部隊数(最大:4) | |
unit_count = 4 | |
# 更新間隔(hh:mm形式) | |
time_interval = '3:00' | |
def time_to_second(x: str) -> int: | |
"""hh:mm形式の文字列を、mmに変換する | |
:param x: str | |
hh:mm形式の時間 | |
:return: | |
mm形式の時間 | |
""" | |
temp = x.split(':') | |
return int(temp[0]) * 60 + int(temp[1]) | |
def ceil(x: int, block: int): | |
"""xをblock単位で切り上げる | |
(参考:Python - 整数1桁5の切り上げのコードを短くしたい | teratail | |
https://teratail.com/questions/131512) | |
:param x: | |
整数 | |
:param block: | |
切り上げ単位 | |
:return: | |
切り上げ単位で切り上げられたx | |
""" | |
return int(math.floor((x + block - 1) / block)) * block | |
# 必要なデータを読み込む | |
exp_table = pandas.read_table('table.tsv') | |
exp_table['分'] = exp_table['時間'].map(lambda x: time_to_second(x)) | |
time_interval_minute = time_to_second(time_interval) | |
exp_table['実質分'] = exp_table['分'].map(lambda x: ceil(x, time_interval_minute)) | |
# 変数(各遠征の回数)を宣言 | |
exp_table['回数'] = [ | |
pulp.LpVariable(f'count_{i}', lowBound=0, cat=pulp.LpInteger) | |
for i in exp_table.index | |
] | |
# 問題の定義を始める | |
problem = pulp.LpProblem("Problem", pulp.LpMinimize) | |
result_time = pulp.LpVariable('result_time', lowBound=0, cat=pulp.LpContinuous) | |
problem += pulp.lpDot(exp_table.実質分, exp_table.回数) <= result_time * unit_count | |
problem += pulp.lpDot(exp_table.人力, exp_table.回数) >= want_supply['人力'] | |
problem += pulp.lpDot(exp_table.弾薬, exp_table.回数) >= want_supply['弾薬'] | |
problem += pulp.lpDot(exp_table.配給, exp_table.回数) >= want_supply['配給'] | |
problem += pulp.lpDot(exp_table.パーツ, exp_table.回数) >= want_supply['パーツ'] | |
for key, row in exp_table.iterrows(): | |
problem += row.実質分 * row.回数 <= result_time | |
problem += result_time | |
# 問題を解く | |
problem.solve() | |
# 結果を表示する | |
exp_table['結果'] = exp_table['回数'].apply(lambda x: pulp.value(x)).astype('int64') | |
exp_table['総時間'] = exp_table.apply(lambda x: x['結果'] * x['実質分'] / 60.0, axis=1) | |
exp_table['人力'] = exp_table.apply(lambda x: x['結果'] * x['人力'], axis=1).astype('int64') | |
exp_table['弾薬'] = exp_table.apply(lambda x: x['結果'] * x['弾薬'], axis=1).astype('int64') | |
exp_table['配給'] = exp_table.apply(lambda x: x['結果'] * x['配給'], axis=1).astype('int64') | |
exp_table['パーツ'] = exp_table.apply(lambda x: x['結果'] * x['パーツ'], axis=1).astype('int64') | |
print(exp_table.query('結果 > 0.0')[['戦役', '名前', '結果', '総時間', '人力', '弾薬', '配給', 'パーツ']]) | |
""" | |
# 変数(連続)を宣言 | |
x = pulp.LpVariable("x", 0, 999, pulp.LpContinuous) | |
y = pulp.LpVariable("y", 0, sys.maxsize, pulp.LpContinuous) | |
# 目的関数を宣言 | |
problem += ( x + y, "Objective" ) | |
# かっこは不要だけど、わかりやすさのため記載 | |
# 制約条件を宣言 | |
problem += ( 2 * x + y <= 2 , "Constraint_1" ) | |
problem += ( x + 2 * y <= 2 , "Constraint_2" ) | |
# 問題の式全部を表示 | |
print("問題の式") | |
print("--------") | |
print(problem) | |
print("--------") | |
# 計算 | |
result_status = problem.solve() | |
# (解が得られていれば)目的関数値や解を表示 | |
print("") | |
print("計算結果") | |
print("********") | |
print("最適性 = {}".format(pulp.LpStatus[result_status])) | |
print("目的関数値 = {}".format(pulp.value(problem.objective))) | |
print("解 x = {}".format(pulp.value(x))) | |
print(" y = {}".format(pulp.value(y))) | |
print("********") | |
""" |
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
ID | 戦役 | 名前 | 人力 | 弾薬 | 配給 | パーツ | Lv | 数 | 時間 | |
---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 応援訓練 | 0 | 145 | 145 | 0 | ? | ? | 0:50 | |
2 | 0 | 合宿訓練 | 550 | 0 | 0 | 35 | 45 | 5 | 3:00 | |
3 | 0 | 特殊支援 | 900 | 900 | 900 | 250 | 45 | 5 | 12:00 | |
4 | 0 | 合同演習 | 0 | 1200 | 800 | 750 | ? | ? | 24:00 | |
5 | 1 | 準備運動 | 10 | 30 | 15 | 0 | ? | ? | 0:15 | |
6 | 1 | 巡回警備 | 0 | 40 | 60 | 0 | ? | ? | 0:30 | |
7 | 1 | 傷者搬送 | 30 | 0 | 30 | 10 | ? | ? | 1:00 | |
8 | 1 | 全域捜索 | 160 | 160 | 0 | 0 | ? | ? | 2:00 | |
9 | 2 | 前線調査 | 100 | 0 | 0 | 20 | 5 | 3 | 0:40 | |
10 | 2 | 後方輸送 | 60 | 200 | 80 | 0 | ? | ? | 1:30 | |
11 | 2 | 工廠配達 | 10 | 10 | 10 | 230 | ? | ? | 4:00 | |
12 | 2 | 資料収集 | 0 | 250 | 600 | 60 | 15 | 5 | 6:00 | |
13 | 3 | 掩体強化 | 50 | 0 | 75 | 0 | ? | ? | 0:20 | |
14 | 3 | 情報入手 | 0 | 120 | 70 | 30 | ? | ? | 0:45 | |
15 | 3 | 交通管制 | 0 | 300 | 0 | 0 | 15 | 4 | 1:30 | |
16 | 3 | 間道封鎖 | 0 | 0 | 300 | 300 | 25 | 5 | 5:00 | |
17 | 4 | 視界支援 | 0 | 185 | 185 | 0 | ? | ? | 1:00 | |
18 | 4 | 供給遮断 | 0 | 0 | 0 | 210 | 35 | 5 | 2:00 | |
19 | 4 | 地図強奪 | 800 | 550 | 0 | 0 | ? | ? | 6:00 | |
20 | 4 | 座標特定 | 400 | 400 | 400 | 150 | ? | ? | 8:00 | |
21 | 5 | 定期検閲 | 0 | 0 | 100 | 45 | ? | ? | 0:30 | |
22 | 5 | 現場救助 | 0 | 600 | 300 | 0 | 35 | 5 | 2:30 | |
23 | 5 | 経路追跡 | 800 | 400 | 400 | 0 | 40 | 5 | 4:00 | |
24 | 5 | 維持工作 | 100 | 0 | 0 | 700 | 40 | 5 | 7:00 | |
25 | 6 | 救援協力 | 300 | 300 | 0 | 100 | 35 | 5 | 2:00 | |
26 | 6 | 遠隔捜査 | 0 | 200 | 550 | 100 | 40 | 5 | 3:00 | |
27 | 6 | 技術抽出 | 0 | 0 | 200 | 500 | 45 | 5 | 5:00 | |
28 | 6 | 戦場捜索 | 800 | 800 | 800 | 0 | ? | ? | 12:00 | |
29 | 7 | 拠点監視 | 650 | 0 | 650 | 0 | ? | ? | 2:30 | |
30 | 7 | 友軍支援 | 0 | 650 | 0 | 300 | 45 | 5 | 4:00 | |
31 | 7 | 交通整理 | 900 | 600 | 600 | 0 | ? | ? | 5:30 | |
32 | 7 | ダミー追跡 | 250 | 250 | 250 | 600 | ? | ? | 8:00 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment