プロスピA イベント「俺の球場飯!!」の食材消費にpulp用いてみた

## はじめに
初投稿になります。今回はスマホゲームの **プロ野球スピリッツA** でのイベント **俺の球場飯!!** で獲得した食材の余り分をなるべく無駄なく消費するためのツールを作ってみたので、備忘録も兼ねた投稿になります。
 **”食材の最適な消費”** という点で、線形計画問題っぽく扱えるんじゃないかとふと思いついたので実装してみました。今回は食材や料理のランク（★1~3）は考慮していません。

## 使うもの
<dl>
<dt>・Python</dt>
<dd></dd>

<dt>・Pulp</dt>
<dd>Pulpは、Pythonで数理最適化のモデルを記述することができるライブラリです。</dd>
<dt>・Flask</dt>
<dd>今回はwebアプリ形式のものも作成し、フレームワークはFlaskを使用しました。</dd>
<dt>・Render.com</dt>
<dd>作成したwebアプリをRender.comにデプロイしました。以前はHerokuを使用していましたが、無料枠の廃止に伴い探した中で個人的に使いやすかったので今回も使用しています。</dd>

</dl>

https://render.com/

## 最適化部分
食材の消費を線形計画問題っぽく扱うためのPulpを用いた最適化部分のコードです。今回は食材の量と料理の数をlistに格納しました。
```diff_python
def optimize(ingredient):
    ### 問題の定義 ###
    #線形計画の定義
    problem = pulp.LpProblem('orenokyuzyomeshi', pulp.LpMaximize)

    #変数定義
    curry = pulp.LpVariable('curry', 0,100,  'Integer') 
    omelet = pulp.LpVariable('omelet', 0,100,  'Integer') 
    gyudon = pulp.LpVariable('gyudon', 0,100,  'Integer') 
    tendon = pulp.LpVariable('tendon', 0,100,  'Integer') 
    sushi = pulp.LpVariable('sushi', 0,100,  'Integer') 
    cheeze_chicken_sandwich = pulp.LpVariable('cheeze_chicken_sandwich', 0,100,  'Integer') 
    fishburger = pulp.LpVariable('fishburger', 0,100,  'Integer') 
    cheeze_hot_dog = pulp.LpVariable('cheeze_hot_dog', 0,100,  'Integer') 
    fish_and_chips = pulp.LpVariable('fish_and_chips', 0,100,  'Integer') 
    meat_sauce = pulp.LpVariable('meat_sauce', 0,100,  'Integer') 
    omusoba = pulp.LpVariable('omusoba', 0,100,  'Integer') 
    niku_udon = pulp.LpVariable('niku_udon', 0,100,  'Integer') 
    noodle = pulp.LpVariable('noodle', 0,100,  'Integer') 
    hamburger = pulp.LpVariable('hamburger', 0,100,  'Integer') 
    ebiten_udon = pulp.LpVariable('ebiten_udon', 0,100,  'Integer') 
    hashimaki = pulp.LpVariable('hashimaki', 0,100,  'Integer') 
    magurodon = pulp.LpVariable('magurodon', 0,100,  'Integer') 
    kushikatu = pulp.LpVariable('kushikatu', 0,100,  'Integer') 
    yakisoba = pulp.LpVariable('yakisoba', 0,100,  'Integer') 
    croquette = pulp.LpVariable('croquette', 0,100,  'Integer') 
    wafu_chicken_cutlet_sandwich = pulp.LpVariable('wafu_chicken_cutlet_sandwich', 0,100,  'Integer') 

    #制約条件
    #ご飯
    problem += curry + omelet + gyudon + tendon + sushi + magurodon <= ingredient[0]
    #パン
    problem += cheeze_chicken_sandwich + fishburger + cheeze_hot_dog + hamburger + wafu_chicken_cutlet_sandwich <= ingredient[1]
    #麺
    problem +=  meat_sauce + omusoba + niku_udon + noodle + ebiten_udon + yakisoba <= ingredient[2]
    #鶏肉
    problem += omelet + cheeze_chicken_sandwich + wafu_chicken_cutlet_sandwich <= ingredient[3]
    #豚肉
    problem += cheeze_hot_dog + noodle + kushikatu + yakisoba <= ingredient[4]
    #牛肉
    problem += gyudon+meat_sauce + niku_udon + hamburger <= ingredient[5]
    #にんじん
    problem += curry + omusoba + niku_udon + croquette <= ingredient[6]
    #たまねぎ
    problem += gyudon + tendon + meat_sauce + hamburger + kushikatu + croquette <= ingredient[7]
    #じゃがいも
    problem += curry + fish_and_chips + croquette <= ingredient[8]
    #キャベツ
    problem += hashimaki + magurodon + yakisoba + wafu_chicken_cutlet_sandwich <= ingredient[9]
    #卵
    problem += omelet + omusoba + noodle + ebiten_udon + hashimaki <= ingredient[10]
    #チーズ
    problem += cheeze_chicken_sandwich + fishburger + cheeze_hot_dog + hashimaki <= ingredient[11]
    #魚
    problem += sushi + fishburger + fish_and_chips + magurodon <= ingredient[12]
    #エビ
    problem += tendon + sushi + fish_and_chips + ebiten_udon + kushikatu <= ingredient[13]

    #目的関数
    problem += curry + omelet + gyudon + tendon + sushi + cheeze_chicken_sandwich + fishburger + cheeze_hot_dog + fish_and_chips + meat_sauce + omusoba + niku_udon + noodle + hamburger + ebiten_udon + hashimaki + magurodon + kushikatu + yakisoba + croquette + wafu_chicken_cutlet_sandwich
    
    ## solve ##
    status = problem.solve()
    
    ## 結果の格納　##
    meal_number = []
    
    meal_number.append(int(curry.value()))
    meal_number.append(int(omelet.value()))
    meal_number.append(int(gyudon.value()))
    meal_number.append(int(tendon.value()))
    meal_number.append(int(sushi.value()))
    meal_number.append(int(cheeze_chicken_sandwich.value()))
    meal_number.append(int(fishburger.value()))
    meal_number.append(int(cheeze_hot_dog.value()))
    meal_number.append(int(fish_and_chips.value()))
    meal_number.append(int(meat_sauce.value()))
    meal_number.append(int(omusoba.value()))
    meal_number.append(int(niku_udon.value()))
    meal_number.append(int(noodle.value()))
    meal_number.append(int(hamburger.value()))
    meal_number.append(int(ebiten_udon.value()))
    meal_number.append(int(hashimaki.value()))
    meal_number.append(int(magurodon.value()))
    meal_number.append(int(kushikatu.value()))
    meal_number.append(int(yakisoba.value()))
    meal_number.append(int(croquette.value()))
    meal_number.append(int(wafu_chicken_cutlet_sandwich.value()))
    
    return meal_number
```
## webアプリの作成
Flaskを利用してwebアプリの作成を行いました。おおまかにですが、フォームから食材の数の入力を受けて、料理の数を出力する形です。フロントは少しhtmlを書いて、Bootstrapを適用しました。フロント関連もこれから勉強していければと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3163462/23ed0c18-9c6f-a69b-a1a7-2b4edda7b6e2.png)


## おわりに
今回はスマホゲームの **プロ野球スピリッツA** でのイベント **俺の球場飯!!** で獲得した食材の余り分をなるべく無駄なく消費するためのツールをPulpを用いて作ってみました。