このブログ内を検索可能

2024年6月26日水曜日

マジカルマインのシミュレーション(4) ペイアウト率及び全消し率

 再度以下のカードを用いてペイアウト率および全消し率を計算する。

1~25の順列25P7通りすべてのパターンをチェックすればよい…のだがなぜかメモリ不足でできないので、ランダムに番号を生成してそれを複数回行い近似値を得ることにした。

ただ、100回回すのに42秒かかるという事態。となると10000回試行するだけでも4200秒と1時間以上かかってしまう。これはさすがにプログラムがしょぼいか…。

とりあえず翌朝まで回してどうなるかみたいので、翌朝7時までは12時間つまり43200秒あるので、100000回くらい試行することはできそうであるからやってみる。

途中経過

600回試行→

宝箱獲得率左から24%、45%、30%、21%、15%、15%

ペイアウト率107%

全消し率0.3%

結論として若干良いカードらしいことが分かる。このカードが出続ければ徐々にメダルが増えていくという理論になる…が100%そんなことはない。



なお我が作った即席の荒いプログラムは以下。全然きれいではないが、とりあえず正しい結果を返しているのでまあそれなりに役には立つ。

numtomat[x_] := {1 + QuotientRemainder[x - 1, 6][[1]], 

  1 + QuotientRemainder[x - 1, 6][[2]]}; group = Table[Table[0, 6], 9];

pos[number_] := 

  For[j = 1, j <= 1, j++, return = {}; 

   For[i = 1, i <= 54, i++, 

    If[num[[numtomat[i][[1]], numtomat[i][[2]]]] == number, 

     return = Append[return, i]]]; Return[return]];

fall[number_] := 

  For[l = 1, l <= 1, l++, eraselist = {}; 

   If[pos[number] != {}, 

    erasegroup = 

     group[[numtomat[pos[number][[1]]][[1]], 

       numtomat[pos[number][[1]]][[2]]]]; 

    For[k = 1, k <= 54, k++, 

     If[erasegroup == group[[numtomat[k][[1]], numtomat[k][[2]]]], 

      eraselist = Append[eraselist, k]]]; Return[eraselist]]];

erase[list_] := 

  For[r = 1, r <= 1, r++, 

   For[i = 1, i <= Length[list], i++, 

    If[list != {}, 

     block[[numtomat[list[[i]]][[1]], numtomat[list[[i]]][[2]]]] = 0; 

     num[[numtomat[list[[i]]][[1]], numtomat[list[[i]]][[2]]]] = 0]; 

    group[[numtomat[list[[i]]][[1]], numtomat[list[[i]]][[2]]]] = 0]; 

   renzoku = Length[list]; retu = RandomInteger[{1, 6}]; 

   Which[renzoku == 7, odds[[retu]] += 0.5, renzoku == 8, 

    odds[[retu]] += 1.5, renzoku == 9, odds[[retu]] += 4, 

    renzoku == 10, odds[[retu]] += 4, renzoku == 11, 

    odds[[retu]] += 9, renzoku == 12, odds[[retu]] += 11.5, 

    renzoku == 13, odds[[retu]] += 14, renzoku >= 14, 

    odds[[retu]] += 5*renzoku - 51]];

haitouall = 0; kakutokuall = {0, 0, 0, 0, 0, 0};

zenkesi = 0; For[times = 1, times <= 100000, times++, 

 in = RandomChoice[Table[i, {i, 1, 25}], 8];

 block = {{3, 1, 1, 1, 2, 2}, {3, 1, 1, 1, 2, 2}, {3, 2, 2, 4, 2, 

    3}, {3, 1, 2, 4, 2, 3}, {3, 1, 2, 4, 3, 3}, {3, 1, 2, 3, 3, 

    2}, {1, 1, 3, 4, 2, 2}, {1, 3, 3, 4, 2, 2}, {3, 3, 4, 4, 4, 4}};

 num = {{0, 0, 20, 2, 0, 0}, {0, 0, 0, 17, 19, 11}, {4, 12, 0, 0, 0, 

    10}, {16, 0, 22, 9, 6, 0}, {0, 0, 21, 23, 8, 0}, {0, 0, 0, 0, 0, 

    3}, {14, 13, 15, 7, 0, 0}, {0, 0, 18, 0, 5, 25}, {24, 0, 1, 0, 0, 

    0}};

 group = Table[Table[0, 6], 9];

 treasure = {5, 2, 2, 2, 2, 5}; odds = {1, 1, 1, 1, 1, 1}; 

 For[lotta = 1, lotta <= 5, lotta++, groupcount = 0; 

  group = Table[Table[0, 6], 9]; For[i = 1, i <= 54, i++,

   If[group[[numtomat[i][[1]], numtomat[i][[2]]]] == 0 && 

      block[[numtomat[i][[1]], numtomat[i][[2]]]] != 0, 

     groupcount += 1; 

     group[[numtomat[i][[1]], numtomat[i][[2]]]] = groupcount;

     pre = post = 0; first = 0; 

     color = block[[numtomat[i][[1]], numtomat[i][[2]]]];

     While[pre != post || first == 0, first = 1;

       pre = Sum[Count[group[[l]], groupcount], {l, 1, 9}];

       For[j = 1, j <= 54, j++, 

        If[group[[numtomat[j][[1]], numtomat[j][[2]]]] == 0, 

         hidari = migi = ue = sita = {0, 0}; 

         If[numtomat[j][[2]] >= 2, 

          hidari = {numtomat[j][[1]], numtomat[j][[2]] - 1}];

         If[numtomat[j][[2]] <= 5, 

          migi = {numtomat[j][[1]], numtomat[j][[2]] + 1}];

         If[numtomat[j][[1]] >= 2, 

          ue = {numtomat[j][[1]] - 1, numtomat[j][[2]]}];

         If[numtomat[j][[1]] <= 8, 

          sita = {numtomat[j][[1]] + 1, numtomat[j][[2]]}];

         If[

          hidari != {0, 0} && 

           block[[hidari[[1]], hidari[[2]]]] == 

            block[[numtomat[j][[1]], numtomat[j][[2]]]] && 

           group[[hidari[[1]], hidari[[2]]]] > 0, 

          group[[numtomat[j][[1]], numtomat[j][[2]]]] = 

           group[[hidari[[1]], hidari[[2]]]]];

         If[

          ue != {0, 0} && 

           block[[ue[[1]], ue[[2]]]] == 

            block[[numtomat[j][[1]], numtomat[j][[2]]]] && 

           group[[ue[[1]], ue[[2]]]] > 0, 

          group[[numtomat[j][[1]], numtomat[j][[2]]]] = 

           group[[ue[[1]], ue[[2]]]]];

         If[

          migi != {0, 0} && 

           block[[migi[[1]], migi[[2]]]] == 

            block[[numtomat[j][[1]], numtomat[j][[2]]]] && 

           group[[migi[[1]], migi[[2]]]] > 0, 

          group[[numtomat[j][[1]], numtomat[j][[2]]]] = 

           group[[migi[[1]], migi[[2]]]]];

         If[

          sita != {0, 0} && 

           block[[sita[[1]], sita[[2]]]] == 

            block[[numtomat[j][[1]], numtomat[j][[2]]]] && 

           group[[sita[[1]], sita[[2]]]] > 0, 

          group[[numtomat[j][[1]], numtomat[j][[2]]]] = 

           group[[sita[[1]], sita[[2]]]]];]]; 

       groupall = 

        Sum[If[group[[numtomat[k]]] == groupcount, Return[1], 

          Return[0]], {k, 1, 54}]; 

       post = Sum[Count[group[[l]], groupcount], {l, 1, 9}];;]];];

  Which[lotta == 1, erase[fall[in[[1]]]]; erase[fall[in[[2]]]]; 

   erase[fall[in[[3]]]], lotta == 2, erase[fall[in[[4]]]]; 

   erase[fall[in[[5]]]], lotta == 3, erase[fall[in[[6]]]], lotta == 4,

    erase[fall[in[[7]]]], lotta == 5, erase[fall[in[[8]]]]]; 

  onemore = 1;

  

  While[onemore == 1, nonmovelist = Table[Table[0, 6], 9]; first = 0; 

   pre = 0; post = 0;

   

   While[pre != post || first == 0, first = 1; 

    pre = Sum[Count[nonmovelist[[l]], 1], {l, 1, 9}]; 

    For[m = 54, m >= 1, m--, 

     If[group[[numtomat[m][[1]], numtomat[m][[2]]]] != 0 && m >= 49, 

      nonmovelist[[numtomat[m][[1]], numtomat[m][[2]]]] = 1]; 

     If[group[[numtomat[m][[1]], numtomat[m][[2]]]] != 0 && 

       numtomat[m][[1]] <= 8 && 

       nonmovelist[[numtomat[m][[1]] + 1, numtomat[m][[2]]]] == 1 && 

       group[[numtomat[m][[1]], numtomat[m][[2]]]] == 

        group[[numtomat[m][[1]] + 1, numtomat[m][[2]]]], 

      nonmovelist[[numtomat[m][[1]], numtomat[m][[2]]]] = 1];

     If[group[[numtomat[m][[1]], numtomat[m][[2]]]] != 0 && 

       numtomat[m][[1]] >= 2 && 

       nonmovelist[[numtomat[m][[1]] - 1, numtomat[m][[2]]]] == 1 && 

       group[[numtomat[m][[1]], numtomat[m][[2]]]] == 

        group[[numtomat[m][[1]] - 1, numtomat[m][[2]]]], 

      nonmovelist[[numtomat[m][[1]], numtomat[m][[2]]]] = 1];

     If[group[[numtomat[m][[1]], numtomat[m][[2]]]] != 0 && 

       numtomat[m][[2]] >= 2 && 

       nonmovelist[[numtomat[m][[1]], numtomat[m][[2]] - 1]] == 1 && 

       group[[numtomat[m][[1]], numtomat[m][[2]]]] == 

        group[[numtomat[m][[1]], numtomat[m][[2]] - 1]], 

      nonmovelist[[numtomat[m][[1]], numtomat[m][[2]]]] = 1];

     If[group[[numtomat[m][[1]], numtomat[m][[2]]]] != 0 && 

       numtomat[m][[2]] <= 5 && 

       nonmovelist[[numtomat[m][[1]], numtomat[m][[2]] + 1]] == 1 && 

       group[[numtomat[m][[1]], numtomat[m][[2]]]] == 

        group[[numtomat[m][[1]], numtomat[m][[2]] + 1]], 

      nonmovelist[[numtomat[m][[1]], numtomat[m][[2]]]] = 1];

     If[group[[numtomat[m][[1]], numtomat[m][[2]]]] != 0 && 

       numtomat[m][[1]] <= 8 && 

       nonmovelist[[numtomat[m][[1]] + 1, numtomat[m][[2]]]] == 1, 

      nonmovelist[[numtomat[m][[1]], numtomat[m][[2]]]] = 1];

     

     ]; post = Sum[Count[nonmovelist[[l]], 1], {l, 1, 9}];]; 

   For[m = 54, m >= 1, m--, 

    If[nonmovelist[[numtomat[m][[1]], numtomat[m][[2]]]] == 0 && 

      group[[numtomat[m][[1]], numtomat[m][[2]]]] > 0, 

     block[[numtomat[m][[1]] + 1, numtomat[m][[2]]]] = 

      block[[numtomat[m][[1]], numtomat[m][[2]]]];

     group[[numtomat[m][[1]] + 1, numtomat[m][[2]]]] = 

      group[[numtomat[m][[1]], numtomat[m][[2]]]];

     num[[numtomat[m][[1]] + 1, numtomat[m][[2]]]] = 

      num[[numtomat[m][[1]], numtomat[m][[2]]]];

     block[[numtomat[m][[1]], numtomat[m][[2]]]] = 0;

     group[[numtomat[m][[1]], numtomat[m][[2]]]] = 0;

     num[[numtomat[m][[1]], numtomat[m][[2]]]] = 0]]; onemore = 0;

   For[s = 1, s <= 54, s++, 

    If[nonmovelist[[numtomat[s][[1]], numtomat[s][[2]]]] == 0 && 

      group[[numtomat[s][[1]], numtomat[s][[2]]]] > 0, 

     onemore = 1]]];];

 groupwin = Table[Table[0, 6], 9]; groupcount = 0;

 For[i = 1, i <= 54, i++,

  If[groupwin[[numtomat[i][[1]], numtomat[i][[2]]]] == 0, 

    groupcount += 1; 

    groupwin[[numtomat[i][[1]], numtomat[i][[2]]]] = groupcount;

    pre = post = 0; first = 0; 

    color = block[[numtomat[i][[1]], numtomat[i][[2]]]];

    While[pre != post || first == 0, first = 1;

      pre = Sum[Count[groupwin[[l]], groupcount], {l, 1, 9}];

      For[j = 1, j <= 54, j++, 

       If[groupwin[[numtomat[j][[1]], numtomat[j][[2]]]] == 0, 

        hidari = migi = ue = sita = {0, 0}; 

        If[numtomat[j][[2]] >= 2, 

         hidari = {numtomat[j][[1]], numtomat[j][[2]] - 1}];

        If[numtomat[j][[2]] <= 5, 

         migi = {numtomat[j][[1]], numtomat[j][[2]] + 1}];

        If[numtomat[j][[1]] >= 2, 

         ue = {numtomat[j][[1]] - 1, numtomat[j][[2]]}];

        If[numtomat[j][[1]] <= 8, 

         sita = {numtomat[j][[1]] + 1, numtomat[j][[2]]}];

        If[

         hidari != {0, 0} && 

          block[[hidari[[1]], hidari[[2]]]] == 

           block[[numtomat[j][[1]], numtomat[j][[2]]]] && 

          groupwin[[hidari[[1]], hidari[[2]]]] > 0, 

         groupwin[[numtomat[j][[1]], numtomat[j][[2]]]] = 

          groupwin[[hidari[[1]], hidari[[2]]]]];

        If[

         ue != {0, 0} && 

          block[[ue[[1]], ue[[2]]]] == 

           block[[numtomat[j][[1]], numtomat[j][[2]]]] && 

          groupwin[[ue[[1]], ue[[2]]]] > 0, 

         groupwin[[numtomat[j][[1]], numtomat[j][[2]]]] = 

          groupwin[[ue[[1]], ue[[2]]]]];

        If[

         migi != {0, 0} && 

          block[[migi[[1]], migi[[2]]]] == 

           block[[numtomat[j][[1]], numtomat[j][[2]]]] && 

          groupwin[[migi[[1]], migi[[2]]]] > 0, 

         groupwin[[numtomat[j][[1]], numtomat[j][[2]]]] = 

          groupwin[[migi[[1]], migi[[2]]]]];

        If[

         sita != {0, 0} && 

          block[[sita[[1]], sita[[2]]]] == 

           block[[numtomat[j][[1]], numtomat[j][[2]]]] && 

          groupwin[[sita[[1]], sita[[2]]]] > 0, 

         groupwin[[numtomat[j][[1]], numtomat[j][[2]]]] = 

          groupwin[[sita[[1]], sita[[2]]]]];]]; 

      groupall = 

       Sum[If[groupwin[[numtomat[k]]] == groupcount, Return[1], 

         Return[0]], {k, 1, 54}]; 

      post = Sum[Count[groupwin[[l]], groupcount], {l, 1, 9}];;]];];

 haitou = 0; kakutoku = {0, 0, 0, 0, 0, 0}; 

 For[i = 49, i <= 54, i++, flug = 0; 

  If[SubsetQ[

      groupwin[[1]], {groupwin[[numtomat[i][[1]], 

         numtomat[i][[2]]]]}] == True && 

    block[[numtomat[i][[1]], numtomat[i][[2]]]] == 0, 

   haitou += odds[[i - 48]]*treasure[[i - 48]]; 

   kakutoku[[i - 48]] = 1]]; 

 If[group == {{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 

     0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 

     0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}, 

  zenkesi += 1]; kakutokuall += kakutoku; haitouall += haitou; 

 If[QuotientRemainder[times, 100][[2]] == 0, 

  Print[{times, N[kakutokuall/times], N[haitouall/times], 

    N[zenkesi/times]}]]]; Print[{N[kakutokuall/times], 

  N[haitouall/times], N[zenkesi/times]}]

マジカルマインのシミュレーション(3) 宝箱獲得処理とオッズアップ

 宝箱のオッズアップはおそらく以下がほぼ正しいと思うのでそれを採用する。

オッズアップはランダムに、獲得済の宝箱にもつく可能性があり以下のテーブルに従う。

7個 +0.5倍

8個 +1.5倍

9個 +4倍

10個 +4倍

11個 +9倍

12個 +11.5倍

13個 +14倍

n個(n>=14) 5*n-51倍 例えばn=14ならば+19倍、n=21ならば54倍

宝箱は最上段の空白と開通しているときに入手できる。そしてオッズを{1,1,1,1,1,1}とし、配当を{5,2,2,2,2,5}などのようにしてそれぞれの宝箱の配当を計算することにする。

宝箱獲得処理については実はグループ分けのプログラムを流用すればよく、これまで空白マスは0としていたがこれをグループ分けすれば、そのグループが上と下でマスがつながっていれば配当獲得となるのである。

すなわち、宝箱の真上に存在するマスのグループが上まで通じている(=上の6マスに最低でも1つ同じグループのマスが存在する)ことを各宝箱でチェックすればよいのである。

よさそうな例は以下。参考youtubeのURL:アニマロッタ8/ロケテスト/マジカルマイン/ファンタジーワンダーチャンス (youtube.com)

これで入った番号は{14, 15, 4, 11, 2, 21, 16, 23}であるが、7球終了時点で以下の状態。
初期値を2つ上の画像のように設定して7球終了時点で番号7つを入れてシミュレートすると以下。当たり前だが完全に一致している。(オッズ配置はたまたま)
オッズアップについては1つが2.5倍、もう1つが12.5倍となっており、下図「オッズ」を見ると確かに場所は違うが、2.5と12.5の表記がある。そして獲得フラグは一番左の列だけちゃんと出ており、3,4,5列目が一見上が空いているようにみえても閉じ込められているので獲得判定になっていないことも確かめられる。なおここの判定には各宝箱の上のマスのグループ番号(空白もグループ化する)が、最上段のグループ番号の組(ここでは{1,1,1,1,1,1})の部分集合であるかどうかを用いている。
これをもって配当の計算ができたので、ペイアウト率及び全消し率も簡単に求めることができる。ペイアウト率はオッズアップがどこにつくかランダムなので完全な正確値ではないが、全消し率は正確に出る。次の記事ではそれについて記述する。

マジカルマインシミュレーション(2) HIT処理と落下処理

 先ほどグループ化の処理を行ったが、HIT処理と落下処理もマジカルマインを構成する重要な処理である。HIT処理についてはHITした番号と同じグループのブロックを消すだけなので実は非常に簡単。

これをグループ化して行列形式にしたものが以下。
1 2 2 2 3 3
1 2 2 2 3 3
1 4 4 5 3 6
1 7 4 5 3 6
1 7 4 5 6 6
1 7 4 6 6 8
7 7 9 10 8 8
7 9 9 10 8 8
9 9 10 10 10 10
確かにグループ分けができており、ここで例えば{13,14,1}にHITしたとするとどうなるか。
グループ7とグループ10のブロックが消えるのでプログラムを構築すると以下になる。
3 1 1 1 2 2
3 1 1 1 2 2
3 2 2 4 2 3
3 0 2 4 2 3
3 0 2 4 3 3
3 0 2 3 3 2
0 0 3 0 2 2
0 3 3 0 2 2
3 3 0 0 0 0
たしかにグループ7とグループ10が消えているのが分かる。

続いて落下処理であるが、これもチェーンボンバーと似たような方式。ただし各ブロックの下にマスがあるかの判定ではなく、各グループのすべてのマスの下にマスがないことが条件となる。
具体的な例を挙げるとすると
〇〇  △△〇
〇××    〇
〇〇×  〇〇
  ××   〇
      〇
ーーーーーーーー
このような状態のとき、一番右の〇グループは動かない。△は1マスだけ落ちる。×は1マス落ち、一番左の〇は1マス落ちる。これをどう処理するか。

まず、グループのいずれかのマスの下に地面があればそのグループは確実に動かない。
それ以外のものは動く「可能性のある」ものとする。
その後、各グループに関してそれらのマスの中に一つでも下に「絶対に動かない」マスがあれば当たり前だがそのグループに属するマスは動かない。
それ以外のマスは1マス分落ちることとなるので
      〇
〇〇  △△〇
〇××   〇〇
〇〇×   〇
  ××   〇
ーーーーーーーー
のようになる。そして再度同じ処理を行うと、今度は×が絶対に動かないマスになり、左の〇と△はともに絶対に動かないマスの上に位置するマスがあるため、動かないこととなる。これで処理は終了する。
以上の考え方をプログラムに適用する。
すると、
1 2 2 2 3 3
1 2 2 2 3 3
1 4 4 5 3 6
1 0 4 5 3 6
1 0 4 5 6 6
1 0 4 6 6 8
0 0 9 0 8 8
0 9 9 0 8 8
9 9 0 0 0 0
のグループに対して(7と10グループは13,14,1番HITにより消えている)
0 1 1 1 0 0
0 1 1 1 0 0
0 1 1 0 0 0
0 0 1 0 0 0
0 0 1 0 0 0
0 0 1 0 0 0
0 0 1 0 0 0
0 1 1 0 0 0
1 1 0 0 0 0
となり(1=停止、0=落ちる)、確かに落ちるor落ちない判定ができている。
そして落ちるブロックをすべて1段ずらしてまた同じ処理を繰り返し、状態が変わらなくなるまで繰り返せば落下処理は確定する。これをプログラムで構築すると
0 1 1 1 0 0
0 1 1 1 0 0
0 1 1 0 0 0
0 0 1 0 0 0
0 0 1 0 0 0
0 0 1 0 0 0
0 0 1 0 0 0
0 1 1 0 0 0
1 1 0 0 0 0
上:1回目落ちるものと落ちないものの区別
下:1マス分落ちた後の状態
0 2 2 2 0 0
1 2 2 2 3 3
1 4 4 0 3 3
1 0 4 5 3 6
1 0 4 5 3 6
1 0 4 5 6 6
1 0 9 6 6 8
0 9 9 0 8 8
9 9 0 0 8 8
そしてその次の操作で
0 1 1 1 0 0
0 1 1 1 1 1
0 1 1 0 1 1
0 0 1 1 1 1
0 0 1 1 1 1
0 0 1 1 1 1
0 0 1 1 1 1
0 1 1 0 1 1
1 1 0 0 1 1
上:2回目落ちるものと落ちないものの区別
下:1マス分落ちた後の状態
0 2 2 2 0 0
0 2 2 2 3 3
1 4 4 0 3 3
1 0 4 5 3 6
1 0 4 5 3 6
1 0 4 5 6 6
1 0 9 6 6 8
1 9 9 0 8 8
9 9 0 0 8 8
確かに右ブロック群は1マス落ち、左ブロック群は2マス落ちていることが分かる。
これにより落下処理は完了したので、いよいよ入賞番号が与えられれば最終的なブロックの配置が確定することになるので、実際に確かめてみる。
ちなみに入賞した番号の順によって結果は変わることに注意する。
具体例として
2 2 1
1 1 2
1 1 2
2 2 3
のカラーであった場合、12マス目→4マス目が消えた場合
2 2 0
1 1 1
1 1 2
2 2 2
からの
0 0 0
0 0 0
2 2 2
2 2 2
になるのに対して、
4マス目→12マス目が消えた場合
0 0 1
0 0 2
2 2 2
2 2 3
からの
0 0 0
0 0 1
2 2 2
2 2 2
になるので違う。

なので最初3球同時消え+2球同時消え+順に1球ずつ3回、に分けなければならない点に注意する。実際の消滅例をいくつか動画のもので試せばプログラムの正確性は保証されてくるのでさっそくやりたい。
すると以下の結果になった。

残っているブロックの位置およびグループ分け、そして番号配置も完全に一致。これを持って我のマジカルマインのブロック関係のプログラムは正しいことがおそらく証明された。

となれば次は宝箱GET判定とオッズアップ判定、そしてオッズ処理を行って期待値計算や全消し確率の計算にもっていく。ここまで来ればほぼ完成に近い状態で、まもなくマジカルマインのペイアウト率が計算できるであろう。


マジカルマインシミュレーション(1) 初期配置データ化とグループ化

カジプロのブラックジャックでは勝てないことも分かったので、テキサスホールデムで他プレイヤーに勝ちまくる作戦を考える前に、少々息抜きでマジカルマインのペイアウト率のシミュレーションを行う。

プログラムなどはいずれ動画化してアップロードする可能性もある。アニマ8のロケテ動画を挙げるものは多く、我はわざわざ川崎まで新幹線で遠征したがあまりプレイしていないので撮れ高はそこまでない。全消しもなければファンタジーJPもない。(ファンタジーJPCは見れて他の人のJPCは結構見れてBGMも堪能できた。なお我はそこそこWCには行ったがJPCには一度も行かなかった)

なおここで注意すべきことは、初期配置とボール入賞番号が与えられたからといって一意に結果が決まるわけではないという点で、その理由はオッズアップがどこの宝箱につくかわからないからである。

しかしながら最終的な配置や全消し率は計算できるので、それらも計算しようと思う。

なおこのプログラムはビンゴガーデンやビンゴファームのようにそこまで簡単ではない。しかしアニマドロップほど難しくはない。かつてアニマ5の通常ゲームをことごとく再現した者にとってはマジカルマインのシミュレーションくらいはたやすい。はず。


ではまず初期配置をデータ化する。今回は赤=1、緑=2、青=3、紫=4として処理し、番号もあわせて格納した6*9*2=108個のデータを作成する。


そして肝心のグループ分けについては以下のモデルを考える。

〇〇〇△△

××〇△〇

×〇〇△〇

×△〇〇〇

これをグループ分けしたい場合どうすればよいか。以前アニマドロップのプログラム構築の際やったのだがだいぶん忘れたので考え直す。

まずグループごとにどこまで続くかをチェックする。

例えば左上に1とつけたならば、その周囲を探索していき隣り合っている番号をチェックする。すなわち1→2→3→8→13→12,18→23→24→25→20→15のように進展する。これを繰り返し、新しいグループ1の所属が増えなくなればグループ分け終了である。

すなわち

1 1 1 0 0

0 0 1 0 1

0 1 1 0 1

0 0 1 1 1

のようになる。

次にグループ1に所属していないもので最初のものを2とつけて探索。

1 1 1 2 2

0 0 1 2 1

0 1 1 2 1

0 0 1 1 1

となる。以下これを繰り返すのみ。これによりグループ分けが完了する。

なお初期配置のグループ分けおよび落下後のグループ分けで、その操作は非常に多く使う。

この手法を用いて上の画像をグループ分けしたものが以下。

{{1,2,2,2,3,3},{1,2,2,2,3,3},{1,4,4,5,3,6},{1,7,4,5,3,6},{1,7,4,5,6,6},{1,7,4,6,6,8},{7,7,9,10,8,8},{7,9,9,10,8,8},{9,9,10,10,10,10}}

確かに10個のグループに分けられていることが分かる。

なお例えば適当に、かなり複雑なグループ分けをしてみると…

〇〇△△××

〇△×△△×

〇×〇〇△×

〇〇〇△△×

〇×△△×〇

〇××××〇

〇×△△×〇

〇×△〇×〇

〇〇〇〇〇〇

上は通常の配置規則を逸脱しているがややこしい例を出すには最適。これを先ほどのプログラムに従ってグループ分けさせると

{{1,1,2,2,3,3},

{1,4,5,2,2,3},

{1,6,1,1,2,3},

{1,1,1,2,2,3},

{1,7,2,2,7,1},

{1,7,7,7,7,1},

{1,7,8,8,7,1},

{1,7,8,1,7,1},

{1,1,1,1,1,1}}

となり、入り組んだ形でも確かにグループ分けできていることが分かる。

2024年6月24日月曜日

カジプロブラックジャック攻略(2) 見せカード毎のディーラーの目期待値

 先ほど初期カードをランダムにして(無限デッキと仮定する)ディーラーの数値分布を行ったが、これの1枚目とその場合の目分布の関係を確認すれば各カード毎の期待値が分かる。

ただしここで注意すべきは、例えば見せカードが1~9と10の数値は明らかに10の方が発生する可能性が高いため、サンプル数では10の方が多く集まるということであるが、1~9を十分な数サンプリングすればおのずと10も十分な数になるのでそれでいく。

その結果、それぞれ見せカードが1~10それぞれの場合でのディーラーの目分布は以下。

やはりA(1)が見せカードの場合はBJの可能性がずば抜けて高い。というのもブラックジャックになるためには10~13の4/13で成立し、かつそうでなくてもまだ特定のカードでBJの確率が加算されるからである。そしてバーストの可能性も明らかに低い。
他には20になる可能性が高いのはやはりもともと10が見せカードであるというのも理にかなっている。

このグラフを見ても明らかに相手の見せ札がA(1)ならば他のパターンより厳しいことが分かり、見せカードが6のときに最も期待値が高そうな雰囲気があるのもわかる。(17以上で止めるため、6の場合は実際は16の可能性が高くその場合のバースト率は8/13とかなり高率だからである)

ディーラーのカードを引くパターンはプレイヤーの数値にかかわらず(無限デッキを仮定しているので)、最初の見せカードの時点でディーラーの目の確率分布は確定する。
すなわち、あらかじめここの確率をより詳細に計算しておくことで以後の確率計算や統計で正確な値が出やすいということになる。
100000回で6秒かかったので、1億回でおそらく6000秒。現実的な回数としては1億回シミュレーションではないかと思われる。

そしてこれを計算させている間に、プレイヤー側の戦略で結果がどう変わってくるかのプログラムを構成していくことにする。








2024年6月17日月曜日

アニマロッタ8 マジカルマインのシミュレーション(2)

しょしん氏が提供する以下の動画によりルールを修正。

https://www.youtube.com/watch?v=YO7E7RdXzwE

まさかのブロックまとまりが1個で出現する場合もあるらしい。


①基本赤青緑紫の4色のブロックで構成される(3色の場合もある)

②それぞれのブロックの個数に規定はない(多いと20個、少ないと4個など)

③各まとまりのブロックの個数は最小1個、最大6個

⑤オッズアップテーブルは同時に消えたクリスタルの数で決まりまだ確定ではないがほぼ以下の規則に従う可能性が高い

7個 +0.5倍

8個 +1.5倍

9個 +4倍

10個 +4倍

11個 +9倍

12個 +11.5倍

13個 +14倍

n個(n>=14) 5*n-51倍 例えばn=14ならば+19倍、n=21ならば54倍

オッズアップ対象はすでにオッズアップ済の宝箱にも、獲得済みの宝箱にもランダムに付与されるものとする。ここでは例として、2WINの宝箱で9個クリスタルによるオッズアップでは2WIN→2+8WIN=10WINとなり、さらに11個消えて同一個所にオッズアップした場合10WIN+(2*9)WIN=28WINになるとする。動画で書かれていた黄色オッズアップ(10個以上すなわち+4倍以上)でも5倍にならないというのはこのことを言っているのではないかと思われる。ただし確定情報ではないので注意。

上記の仮定を満たせば、各配置のペイアウト率はかなり正確に計算できることになる。ただしオッズアップ位置が不明なので数字入賞と配当が1対1対応するわけではなく理論値は出てこない点に留意。

さてここまで仮定が進めばいよいよプログラミングに取り掛かることができる。

分かりやすいようにまずは各ブロックの状況を視覚化できるプログラムなどから作成していき、このゲームの真の特性を暴こうと思う。





なんばOIOIにあるクレーンコーナー「PALO」

 いつの間にかなんばのOIOIにクレーンゲームコーナーができていた。

そしてどれくらいとれるかと両替をしてスウィートランドをプレイしたり確率機をやってみると…。

まさかのスウィートランドではなん百円使っても何一つつかめず(シャベルの角度がかなり反時計回りにしめられているので滑り落ちる)、しかも手前には反り返った透明のシールド、確率機に至ってはつかむ云々の話ではなくほぼ1mmも持ち上がらない。要するに景品をやさしくなでるのを見つけるゲームである。

700円使ったがあまりのカオスさに笑いすら出てしまうレベルで、即座に退散した。当たり前だがもう二度と行くことはない。

そもそもPALO自体がモーリー系列なのでこういう結果になるのは想像に難くないが…。

それにしてもここまでひどいゲームコーナーはなかなかない。350店舗くらいで景品を取っているがここはあのナムコやGIGOより渋く悪質である。ただし、絶対に取れないというイメージがつかみやすいので無駄な散財は防げる。その点ではある意味いい店舗。

そういえば阿倍野の地下にも同じPALOが最近できたとのことだが、なんばのこの惨状を見て察した。

鳥取のPALOなどはまだちゃんと取れる設定のものがあったのだが…。さすが都会。そのためか土曜日なのに閑散としていた。倉庫系などは東北の田舎でも大盛況で景品を袋いっぱいに持つ人ばかり。逆に景品が取れない方が珍しいのにこの差。

結論: PALOは金を捨てる場所


直近に行ったわくわくアミーゴ尾崎と合わせて、やはり府内で設定の良いゲームセンターはもはや結屋、わくわくアミーゴ尾崎の結屋系列しかない。トップランも取りにくくなったし、アミパラ大東もヨッシーが青天井と信じられない(松山や光明池は定価とほぼ同じ設定だった)。日本橋やなんばのタイトーも渋いが、さすがにナムコやGIGOほどではない。

なおOIOIに行った目的はPCの購入であり、例のアレを行うためのPCは15台から17台へとパワーアップ。同級生の時給4000円や半月19万のアルバイトごときに負けないためにさらなるパワーアップを行っている。




2024年6月4日火曜日

東京遠征(n回目)

 やはり東京に行き、ディズニーに行く…わけもなく、以前言っていた店舗と観光名所に突撃。もちろん1泊しかできないので当然ながら始発の新幹線である。

行った店舗および観光地は以下

1日目

シルクハット川崎→ベネクス川崎→タイトー川崎ラチッタデッラ→ルイーダ→イオン幕張新都心→千葉鑑定団湾岸習志野→宇都宮宿泊

2日目

おたちゅう日立南→日立オリジンパーク(小平記念館)→国営ひたち海浜公園→ダイレクト帰宅


では各店舗の印象および紹介。

シルクハット川崎…谷尾年が渋すぎて5000円でも取れない。結局サポートしてもらうことになるが店員の好意で2個取らせてもらえた。ここは設定が近くのモアーズと同様ありえないほど渋いが、実は店員の声は店内にあえて漏らしており、サポートなどが行き届いているということを店中にアピールする効果がある。すなわち我にかなり良いサポートをしてくれた=この店では積極的にサポートをしているというアピールになり、まさに店も客も我もwin-win-winなのである。これに関して文句はない。まあそれでも1個景品2500円なので相当食われているが、取れればもう別に何でもよい。

で肝心のアニマはどうかというと、朝イチにいけばさすがの土曜日でも普通にあいていた。そして我はJPCに一度も行かなかったが他の人は何回か行っていたのでネタには尽きなかった。ロケテストなので自分がJPを取るかというよりもJPCの動画を収めることに意味があるのである。3000円で3時間弱プレイできたので、少なくともコナステよりは設定はよい。

ベネクス川崎…東京えの遠征での入試前日にあそびツナガビンゴトレジャーオールラインというすさまじい運を使ったが入試も当然受かった伝説の店舗。ベネクス系列よろしく取れないというとちゃんと店員はプレイしてくれるし、取れなさそうならサポートもかなりはやい段階でしてくれるのは系列共通。ただやはり最近どこのベネクスでも感じるが、詰みの形になることが多く自力GETはかなり難しい印象。どの景品もサポートありで基本2000円くらいかかり、安く取れたものはほぼない。こういうことが何回も多発するので最近ベネクスには行かなくなったが、それでもサポート体制が良いのでそこらでプレイするよりはよほどまし。あと一番うれしいのは景品の配送サービスを行っているところ。段ボールはプライズのロットの梱包箱のあまりを使うので段ボール代がかからないのが良い。ただし着払いだけだが。これでぬいぐるみなどの大きいぬいぐるみや大きなお菓子セットを配送できる。この点とサポート体制に関してはベネクスが最高。取れやすさ単体で言うなら微妙ではあるが。なおユウヤ師が取ろうとしていたいぶりがっこチーズタルタル(秋田で非常によくみかけるチーズディップとは異なる)はここで見かけたので取った。

タイトー川崎ラチッタデッラ…川崎のラチッタデッラという商業施設でどでかくあるタイトーなので絶対あかんやつやと思ったがそうではなく、タイトーにしてはパワーが入っており昔のベネクスのようなやさしさを感じた。ただ徳島のGIGO、岩手のマッハランドの前例があるのでこの1回だけで野放しに取れる店舗、と断定はできない。何しろ大手なので。

千葉鑑定団湾岸習志野…ユウヤ師のジュースやいぶりがっこチーズタルタルの店。しかしベネクスでいぶりがっこを取っていたのでここではとらなかった。あおさバターはさすがになんかあまりおいしそうな気がしないような。ここはやはり景品が取れやすく、橋渡しも優しい。やはり安心の倉庫系の雰囲気で非常に楽しんだ。なお楽しく遊びすぎて宇都宮に行くための最終新幹線がもう間に合わないことに気づき、在来線最終に乗ることになる…がそれも人身事故で90分遅延して宇都宮着が2時半になるという異例の事態発生。

おたちゅう日立南…JINstudioで紹介されていたので行った。残念ながらほしい景品が少なかった。フルーチェ6個はフック設定で1700円で取れたが原価以上。ただ平均的にはもうちょっと安く取れそう。これは朝食のためにとったが6個で1.2kgなのでそれをもって600km移動するのは重かった。ほかの確率機はまあそれなりの設定で、普通に倉庫系としてまあいい感じの印象を受けた。都会のGIGOやナムコは立地の恩恵があってもかなり閑散としているがこのあたりは田舎なのに大盛況。客はみんな袋いっぱいの景品を持っていることが多い。自宅周辺にもこのような倉庫系があればどれだけうれしいか…。しかし最寄りで北神戸、加古川や長浜となり行くのに2時間はかかるのが残念過ぎる。

国営ひたち海浜公園…ここのゲームコーナーは想像に反してちゃんと取れる設定。基本遊園地のクレーンは渋い印象だが、マリーナシティも生駒山上も、あしかがフラワーパークも東武動物公園もここも案外そこらのゲームセンターよりはちゃんと取れる。ただラインナップは期待してはいけないが。ひよこのようなぬいぐるみを3個GET。去年あたりにドミー知立(愛知)やアピタ蒲郡、ハピピランド日向で手に入れたやつとたぶん同じタイプのもの。スウィートランドもちゃんとおもりは動き、どこぞの落とし口付近に姑息にも滑り止めをつけたりして延々動かない店舗に比べると良心的。

今回のクレーン使用金額は40000円弱。まあ使ってないこともないし使いすぎたわけでもない。なんか毎週試験前以外は遠征している気がするが、それもこれもアレのおかげである。

景品を獲得した店舗もついに340店舗となり、もはや遠征レベルで言うとユウヤ師に並んでいるレベル。技能と知名度はお察しだが…。


来週はディズニー新エリア発生なので東京は混雑が見込まれて危険。というよりまた試験前になるので来週はおとなしくしており、またその後1泊で博多やハウステンボスあたりの西側や日立再訪および千葉東側開拓なども順次行っていく。カービィカフェもそろそろ行きたいが東京のカービィカフェがあかなさすぎる。まあ博多に行けばいいだけの話なのであまり気にしてない。


小平記念館もついでに行き、ここは日立製作所の歴史が見られる場所。個人的にはエスカレーターやエレベーター、医療機器(僧帽弁逆流症などでよく出てくるやつすなわちカラードプラ、重粒子線治療などの機械)、券売機システムMALS、アナログ計算機などとやはりすばらしい発明品ばかりであった。埼玉で展示されていたお召列車も「日立」とあったのでやはり日立の名はだてではない。