OSDN Git Service

[Implement] #41001 hradish氏提供のオートローラー(新確率表記)を実装。 / New autoroller function.
authoriks <iks@users.sorceforge.jp>
Mon, 23 Nov 2020 08:38:06 +0000 (17:38 +0900)
committeriks <iks@users.sorceforge.jp>
Mon, 23 Nov 2020 08:38:06 +0000 (17:38 +0900)
src/birth/auto-roller.c
src/birth/auto-roller.h
src/birth/birth-stat.c
src/birth/birth-wizard.c
src/view/display-birth.c

index 37eee7d..33cb6cd 100644 (file)
@@ -21,6 +21,7 @@ s32b stat_match[6];
 
 /*! オートローラの試行回数 / Autoroll round */
 s32b auto_round;
+s32b auto_upper_round;
 
 /*!
  * @brief オートローラで得たい能力値の基準を決める。
@@ -29,17 +30,20 @@ s32b auto_round;
  */
 bool get_stat_limits(player_type *creature_ptr)
 {
+    int col_stat = 25;
+
     clear_from(10);
     put_str(_("最低限得たい能力値を設定して下さい。", "Set minimum stats."), 10, 10);
     put_str(_("2/8で項目選択、4/6で値の増減、Enterで次へ", "2/8 for Select, 4/6 for Change value, Enter for Goto next"), 11, 10);
     put_str(_("         基本値  種族 職業 性格     合計値  最大値", "           Base   Rac  Cla  Per      Total  Maximum"), 13, 10);
 
+    put_str(_("確率: 非常に容易(1/10000以上)", "Prob: Quite Easy(>1/10000)"), 23, col_stat);
+
     int cval[6];
     char buf[80];
     char cur[80];
     char inp[80];
     for (int i = 0; i < A_MAX; i++) {
-        stat_match[i] = 0;
         cval[i] = 3;
         int j = rp_ptr->r_adj[i] + cp_ptr->c_adj[i] + ap_ptr->a_adj[i];
         int m = adjust_stat(17, j);
@@ -62,7 +66,17 @@ bool get_stat_limits(player_type *creature_ptr)
     int os = 6;
     while (TRUE) {
         if (cs != os) {
-            if (os == 6) {
+            if (os == 7) {
+                autoroll_chance = get_autoroller_prob(cval);
+                if (autoroll_chance == -999)
+                    sprintf(buf, _("確率: 不可能(合計86超)       ", "Prob: Impossible(>86 tot stats)"));
+                else if (autoroll_chance < 1)
+                    sprintf(buf, _("確率: 非常に容易(1/10000以上)", "Prob: Quite Easy(>1/10000)     "));
+                else
+                    sprintf(buf, _("確率: 約 1/%8d00          ", "Prob: ~ 1/%8d00            "), autoroll_chance);
+                put_str(buf, 23, col_stat);
+            }
+            else if (os == 6) {
                 c_put_str(TERM_WHITE, _("決定する", "Accept"), 21, 35);
             } else if (os < A_MAX) {
                 c_put_str(TERM_WHITE, cur, 14 + os, 10);
@@ -176,7 +190,7 @@ bool get_stat_limits(player_type *creature_ptr)
             break;
         }
 
-        if (c == ESCAPE || ((c == ' ' || c == '\r' || c == '\n') && cs == 6))
+        if (c == ESCAPE || ((c == ' ' || c == '\r' || c == '\n') && cs == 6 && autoroll_chance != -999))
             break;
     }
 
@@ -441,3 +455,83 @@ bool get_chara_limits(player_type *creature_ptr, chara_limit_type *chara_limit_p
     chara_limit_ptr->scmax = (s16b)cval[7];
     return TRUE;
 }
+
+/*
+ * @breif オートローラーで指定した能力値以上が出る確率を計算する。
+ * @return 確率 / 100
+ */
+ static s32b get_autoroller_prob(int *minval)
+{
+    /* 1 percent of the valid random space (60^6 && 72<sum<87) */
+    s32b tot_rand_1p = 320669745;
+    int i, j, tmp;
+    int ii[6];
+    int tval[6];
+    int tot = 0;
+
+    /* success count */
+    s32b succ = 0;
+
+    /* random combinations out of 60 (1d3+1d4+1d5) patterns */
+    int pp[18] = {
+        0, 0, 0, 0, 0, 0, 0, 0, /* 0-7 */
+        1, 3, 6, 9, 11, 11, 9, 6, 3, 1 /* 8-17 */
+    };
+
+    /* Copy */
+    for (i = 0; i < 6; i++) 
+    {
+        tval[i] = MAX(8, minval[i]);
+        tot += tval[i];
+    }
+
+    /* No Chance */
+    if (tot > 86) return -999;
+
+    /* bubble sort for speed-up */
+    for (i = 0; i < 5; i++) 
+    {
+        for (j = 5; j > i; j--) 
+        {
+            if (tval[j - 1] < tval[j]) 
+            {
+                tmp = tval[j - 1];
+                tval[j - 1] = tval[j];
+                tval[j] = tmp;
+            }
+        }
+    }
+
+    tot = 0;
+
+    /* calc. prob. */
+    for (ii[0] = tval[0]; ii[0] < 18; ii[0]++) 
+    {
+        for (ii[1] = tval[1]; ii[1] < 18; ii[1]++) 
+        {
+            for (ii[2] = tval[2]; ii[2] < 18; ii[2]++) 
+            {
+                for (ii[3] = tval[3]; ii[3] < 18; ii[3]++) 
+                {
+                    for (ii[4] = tval[4]; ii[4] < 18; ii[4]++) 
+                    {
+                        for (ii[5] = tval[5]; ii[5] < 18; ii[5]++) 
+                        {
+                            tot = ii[0] + ii[1] + ii[2] + ii[3] + ii[4] + ii[5];
+
+                            if (tot > 86) break;
+                            if (tot <= 72) continue;
+
+                            succ += (pp[ii[0]] * pp[ii[1]] * pp[ii[2]] * pp[ii[3]] * pp[ii[4]] * pp[ii[5]]);
+
+                            /* If given condition is easy enough, quit calc. to save CPU. */
+                            if (succ > 320670) return -1;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return tot_rand_1p / succ;
+}
index 189cd34..054b626 100644 (file)
@@ -13,6 +13,20 @@ typedef struct {
 extern s16b stat_limit[6];
 extern s32b stat_match[6];
 extern s32b auto_round;
+extern s32b auto_upper_round;
+
+/*! オートローラの要求値実現確率 */
+static s32b autoroll_chance;
+
+/* emulate 5 + 1d3 + 1d4 + 1d5 by randint0(60) */
+static BASE_STATUS rand3_4_5[60] = {
+    8, 9, 9, 9, 10, 10, 10, 10, 10, 10, /*00-09*/
+    11, 11, 11, 11, 11, 11, 11, 11, 11, 12, /*10-19*/
+    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, /*20-29*/
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, /*30-49*/
+    13, 14, 14, 14, 14, 14, 14, 14, 14, 14, /*40-49*/
+    15, 15, 15, 15, 15, 15, 16, 16, 16, 17 /*50-59*/
+};
 
 bool get_stat_limits(player_type *creature_ptr);
 void initialize_chara_limit(chara_limit_type *chara_limit_ptr);
index 7d7ad27..290e59f 100644 (file)
@@ -1,4 +1,5 @@
 #include "birth/birth-stat.h"
+#include "birth/auto-roller.h"
 #include "core/player-redraw-types.h"
 #include "sv-definition/sv-weapon-types.h"
 #include "player/player-class.h"
@@ -56,39 +57,17 @@ void get_stats(player_type* creature_ptr)
             s32b tmp = randint0(60 * 60 * 60);
             BASE_STATUS val;
 
-            /* Extract 5 + 1d3 + 1d4 + 1d5 */
-            val = 5 + 3;
-            val += tmp % 3;
-            tmp /= 3;
-            val += tmp % 4;
-            tmp /= 4;
-            val += tmp % 5;
-            tmp /= 5;
-
-            sum += val;
-            creature_ptr->stat_cur[3 * i] = creature_ptr->stat_max[3 * i] = val;
-
-            /* Extract 5 + 1d3 + 1d4 + 1d5 */
-            val = 5 + 3;
-            val += tmp % 3;
-            tmp /= 3;
-            val += tmp % 4;
-            tmp /= 4;
-            val += tmp % 5;
-            tmp /= 5;
-
-            sum += val;
-            creature_ptr->stat_cur[3 * i + 1] = creature_ptr->stat_max[3 * i + 1] = val;
-
-            val = 5 + 3;
-            val += tmp % 3;
-            tmp /= 3;
-            val += tmp % 4;
-            tmp /= 4;
-            val += (BASE_STATUS)tmp;
-
-            sum += val;
-            creature_ptr->stat_cur[3 * i + 2] = creature_ptr->stat_max[3 * i + 2] = val;
+            for (int j = 0; j < 3; j++) {
+                int stat = i * 3 + j;
+
+                /* Extract 5 + 1d3 + 1d4 + 1d5 */
+                val = rand3_4_5[tmp % 60];
+
+                sum += val;
+                creature_ptr->stat_cur[stat] = creature_ptr->stat_max[stat] = val;
+
+                tmp /= 60;
+            }
         }
 
         if ((sum > 42 + 5 * 6) && (sum < 57 + 5 * 6))
index b9cf44d..bc56e7d 100644 (file)
@@ -44,7 +44,7 @@
  * system may have problems because the user can't stop the
  * autoroller for this number of rolls.
  */
-#define AUTOROLLER_STEP 5431L
+#define AUTOROLLER_STEP 54321L
 
 static void display_initial_birth_message(player_type *creature_ptr)
 {
@@ -281,16 +281,30 @@ static void display_auto_roller_success_rate(const int col)
     if (!autoroller)
         return;
 
-    put_str(_("最小値", " Limit"), 2, col + 5);
-    put_str(_("成功率", "  Freq"), 2, col + 13);
+    put_str(_("最小値", " Limit"), 2, col + 13);
     put_str(_("現在値", "  Roll"), 2, col + 24);
+
+    char buf[32];
+
+    if (autoroll_chance >= 1)
+        sprintf(buf, _("確率 :  1/%8d00", "Prob :  1/%8d00"), autoroll_chance);
+    else if (autoroll_chance == -999)
+        sprintf(buf, _("確率 :     不可能", "Prob :     Impossible"));
+    else
+        sprintf(buf, _("確率 :     1/10000以上", "Prob :     >1/10000"));
+    put_str(buf, 11, col + 10);
+
+    put_str(_(
+        "注意 : 体格等のオートローラを併用時は、上記確率より困難です。",
+        "Note : Prob may be lower when you use the 'autochara' option."
+        ), 22, 5);
+
     for (int i = 0; i < A_MAX; i++) {
-        put_str(stat_names[i], 3 + i, col);
+        put_str(stat_names[i], 3 + i, col + 8);
         int j = rp_ptr->r_adj[i] + cp_ptr->c_adj[i] + ap_ptr->a_adj[i];
         int m = adjust_stat(stat_limit[i], j);
-        char buf[32];
         cnv_stat(m, buf);
-        c_put_str(TERM_L_BLUE, buf, 3 + i, col + 5);
+        c_put_str(TERM_L_BLUE, buf, 3 + i, col + 13);
     }
 }
 
@@ -303,9 +317,7 @@ static void auto_roller_count(void)
     if (!autoroller)
         return;
 
-    for (int i = 0; i < A_MAX; i++) {
-        stat_match[i] = 0;
-    }
+    auto_upper_round++;
 }
 
 static bool decide_initial_stat(player_type *creature_ptr)
@@ -315,10 +327,10 @@ static bool decide_initial_stat(player_type *creature_ptr)
 
     bool accept = TRUE;
     for (int i = 0; i < A_MAX; i++) {
-        if (creature_ptr->stat_max[i] >= stat_limit[i])
-            stat_match[i]++;
-        else
+        if (p_ptr->stat_max[i] < stat_limit[i]) {
             accept = FALSE;
+            break;
+        }
     }
 
     return accept;
@@ -352,7 +364,10 @@ static bool display_auto_roller_count(player_type *creature_ptr, const int col)
         return FALSE;
 
     birth_put_stats(creature_ptr);
-    put_str(format("%10ld", auto_round), 10, col + 20);
+    if (auto_upper_round)
+        put_str(format("%ld%09ld", auto_upper_round, auto_round), 10, col + 20);
+    else
+        put_str(format("%10ld", auto_round), 10, col + 20);
     term_fresh();
     inkey_scan = TRUE;
     if (inkey()) {
@@ -444,11 +459,11 @@ static bool display_auto_roller(player_type *creature_ptr, chara_limit_type char
     bool prev = FALSE;
 
     while (TRUE) {
-        int col = 42;
+        int col = 22;
         if (autoroller || autochara) {
             term_clear();
-            put_str(_("回数 :", "Round:"), 10, col + 13);
-            put_str(_("(ESCで停止)", "(Hit ESC to stop)"), 12, col + 13);
+            put_str(_("回数 :", "Round:"), 10, col + 10);
+            put_str(_("(ESCで停止)", "(Hit ESC to stop)"), 13, col + 13);
         } else {
             get_stats(creature_ptr);
             get_ahw(creature_ptr);
@@ -522,8 +537,11 @@ bool player_birth_wizard(player_type *creature_ptr, void (*process_autopick_file
         return FALSE;
 
     display_initial_options(creature_ptr);
-    if (autoroller || autochara)
+    if (autoroller || autochara) {
         auto_round = 0L;
+        auto_upper_round = 0L;
+        autoroll_chance = 0L;
+    }
 
     if (autoroller)
         if (!get_stat_limits(creature_ptr))
index 5318c62..0632553 100644 (file)
@@ -18,20 +18,12 @@ void birth_put_stats(player_type *creature_ptr)
     if (!autoroller)
         return;
 
-    const int col = 42;
+    const int col = 22;
     for (int i = 0; i < A_MAX; i++) {
         int j = rp_ptr->r_adj[i] + cp_ptr->c_adj[i] + ap_ptr->a_adj[i];
         int m = adjust_stat(creature_ptr->stat_max[i], j);
         char buf[80];
         cnv_stat(m, buf);
         c_put_str(TERM_L_GREEN, buf, 3 + i, col + 24);
-        if (stat_match[i]) {
-            int p = stat_match[i] > 1000000L ? stat_match[i] / (auto_round / 1000L) : 1000L * stat_match[i] / auto_round;
-            TERM_COLOR attr = (p < 100) ? TERM_YELLOW : TERM_L_GREEN;
-            sprintf(buf, "%3d.%d%%", p / 10, p % 10);
-            c_put_str(attr, buf, 3 + i, col + 13);
-        } else {
-            c_put_str(TERM_RED, _("(なし)", "(NONE)"), 3 + i, col + 13);
-        }
     }
 }