【原神】ラグランジュの未定乗数法による理想ステータス配分の計算~実装編~

CASIOのkeisanで現在のステータスを再配分して理想ステータスがどのようなステータスか計算するツールを実装しました.
これを使えば不足しているステータスがすぐにわかるので聖遺物付け替えやパーティーバフ検討の目安になるかと思います.
keisan.casio.jp


計算の理論を知りたい方はこちらをご参照ください.
fumofumobun-study.hatenablog.com


またそのもととなった記事
fumofumobun-study.hatenablog.com
fumofumobun-study.hatenablog.com

も興味があればご参照下さい.

今回はこの計算のコードを載せます.
変数だけ解説しておきます.
まず添字_beforeは現在のステータスです(入力).ついてないものは定数か,算出される理想ステータス等です.
batk:基礎攻撃力a_b
atk:最終攻撃力A(a_r)
atkrate:攻撃力%a_r
critrate:会心c_r
critdmg:会心ダメージc_d
dmgbuff:ダメージバフd_b
status_total:合計ステータス量s
t:計算途中で置いた場合分けに使用するパラメータt



atkrate_before = ((atk_before-311)/batk) - 1.0;    /*攻撃力%*/
status_total = 4*(atkrate_before + 0.01*dmgbuff_before) + 0.06*critrate_before + 0.03*critdmg_before;     /*合計ステータス*/
dmgbuff_fixed = do_you_fix;     /*ダメバフを変動させるか? 変動は0 固定は1*/
ascensionstatus = which_ascensionstatus;    /*突破ステは? 非会心系なら0 会心率は1 会心ダメは2*/

if(dmgbuff_fixed == 0){ /*ダメバフ変動*/
    t = (8 + status_total + (1244/batk))/6;   /*計算上便利な変数*/
    if(t > 0 and t < 4){    /*ステータス不足の場合*/
        if(ascensionstatus == 0){ /*突破ステによって場合わけ*/
            critrate = 0.05;
            critdmg = 0.5;        
            atkrate = 0.5*(0.25*(status_total - 1.8) - 311/batk);
            dmgbuff = atkrate + 311/batk;
            
        }elseif(ascensionstatus == 1){
            critrate = 0.242;
            critdmg = 0.5;        
            atkrate = 0.5*(0.25*(status_total - 2.952) - 311/batk);
            dmgbuff = atkrate + 311/batk;
            
        }elseif(ascensionstatus == 2){
            critrate = 0.05;
            critdmg = 0.884;        
            atkrate = 0.5*(0.25*(status_total - 2.952) - 311/batk);
            dmgbuff = atkrate + 311/batk;
           
        }
        
    }elseif(t >= 4 and t =< 5){     /*平均的なステータスの場合*/
        critrate = (t + sqrt(t*t - 16))/8;
        critdmg = 2.0*critrate;
        atkrate = 0.75*(2*critrate + 1/critrate) - 311/batk - 1.0;
        dmgbuff = atkrate + 311/batk;
        
    }elseif(t > 5){   /*ステータス十分の場合*/
        critrate = 1.0;
        critdmg = (status_total + 1244/batk - 4)/9;
        atkrate = 0.75*critdmg -311/batk - 0.25;
        dmgbuff = atkrate + 311/batk;
    }
    
    
}elseif(dmgbuff_fixed == 1){    /*ダメバフ固定*/
    dmgbuff = 0.01*dmgbuff_before;
    status_total = status_total - 4*dmgbuff; /*固定したダメバフを合計ステータスから差し引く*/
    t = (4 + status_total + (1244/batk))/6;   /*計算上便利な変数*/
    /*突破ステによって場合分けパラメータの変更*/
    if(ascensionstatus == 0){
        u = 2.51;
        
    }elseif(ascensionstatus == 1){
        u = 2.50;
        
    }elseif(ascensionstatus == 2){
        u = 2.065;
        
    }
    
    if(t > 0 and t < u){    /*ステータス不足の場合*/
        if(ascensionstatus == 0){
            critrate = 0.05;
            critdmg = 0.5;        
            atkrate = 0.25*(status_total - 1.8);
            
        }elseif(ascensionstatus == 1){
            critrate = 0.242;
            critdmg = 0.5;        
            atkrate = 0.25*(status_total - 2.952);
            
        }elseif(ascensionstatus == 2){
            critrate = 0.05;
            critdmg = 0.884;        
            atkrate = 0.25*(status_total - 2.952);
           
        }
        
    }elseif(t >= u and t =< 3.5){     /*平均的なステータスの場合*/
        if(ascensionstatus == 0 or ascensionstatus == 1 or (ascensionstatus == 2 and t > 2.449)){
            critrate = (t + sqrt(t*t - 6))/6;
            critdmg = 2.0*critrate;
            atkrate = 0.75*(2*critrate + 1/critrate) - 311/batk - 1.0;
        
        }elseif(ascensionstatus == 2 and t =< 2.449){
            critrate = 0.442;
            critdmg = 0.884;        
            atkrate = 0.25*(status_total - 5.304);
        }
        
    }elseif(t > 3.5){   /*ステータス十分の場合*/
        critrate = 1.0;
        critdmg = (status_total + 1244/batk - 5)/6;
        atkrate = 0.75*critdmg -311/batk - 0.25;
        
    }
    
}

atk = (1.0 + atkrate)*batk + 311;   /*理想最終攻撃力*/


/*理想ステータス出力*/
print(int(atk));
print(round(critrate*100,1));
print(round(critdmg*100,1));
print(round(dmgbuff*100,1));

/*期待値比較*/
exdmg_before = atk_before*(1 + 0.01*critrate_before*0.01*critdmg_before)*(1 + 0.01*dmgbuff_before);
exdmg = atk*(1 + critrate*critdmg)*(1 + dmgbuff);
print(int(exdmg_before));
print(int(exdmg));
print(round(exdmg/exdmg_before,3));

こんな感じです.可読性よく書いたつもりなので逐一解説はしません.
ご質問・ご指摘あれば遠慮なくコメント下さい.