2021年12月27日月曜日

D2メガテンの烙印の失敗がどの程度かモデルで検証してみた。

どうも、あまりにも失敗が目立って酷いので、コードを書いて検証してみることにした。

烙印のステータスアップの成功率 10% に対して40回以上失敗が連続するのは、どの程度で、最高何回ぐらい続くのか?
#include <iostream>
#include <random>
#include <array>
#include <algorithm>
#include <numeric>
#include <vector>

#define TRY_COUNT 10000

using seed_v_t = std::array<std::random_device::result_type, sizeof(std::mt19937)/sizeof(std::random_device::result_type)>;
seed_v_t create_seed_v() {
  std::random_device rnd;
  seed_v_t sed_v;
  std::generate(sed_v.begin(), sed_v.end(), std::ref(rnd));
  return sed_v;
}


std::mt19937 create_random_engine()
{
  const auto sed_v = create_seed_v();
  std::seed_seq seq(sed_v.begin(), sed_v.end());
  return std::mt19937(seq);
}

std::mt19937& random_engine()
{
  static thread_local std::mt19937 engine = create_random_engine();
  return engine;
}

int main() {
  std::mt19937& engine = random_engine();
  std::uniform_int_distribution<int> dist(0, 10);
  std::vector<int> cnts;
  int bingo = 0;
  int cnt = 0;
  for(int i = 0; i < TRY_COUNT; ++i) {
    int val = dist(engine);
    if( val != 0 ) ++cnt;
    else {
      cnts.push_back( cnt );
      cnt = 0;
    }
  }
  int acc = std::accumulate( cnts.begin(), cnts.end(), 0);
  std::cout << std::endl;
  std::cout << "成功回数         = " << cnts.size() << " / " << TRY_COUNT << std::endl;
  std::cout << "平均施行回数     = " << (acc / (double)cnts.size()) << std::endl;
  std::cout << "31回以上連続失敗 = " << std::count_if( cnts.begin(), cnts.end(), [](int x) { return (x > 30); } ) << std::endl;
  std::cout << "41回以上連続失敗 = " << std::count_if( cnts.begin(), cnts.end(), [](int x) { return (x > 40); } ) << std::endl;
  std::cout << "51回以上連続失敗 = " << std::count_if( cnts.begin(), cnts.end(), [](int x) { return (x > 50); } ) << std::endl;
  std::cout << "61回以上連続失敗 = " << std::count_if( cnts.begin(), cnts.end(), [](int x) { return (x > 60); } ) << std::endl;
  std::cout << "71回以上連続失敗 = " << std::count_if( cnts.begin(), cnts.end(), [](int x) { return (x > 70); } ) << std::endl;
  std::cout << "最大連続失敗回数 = " << *std::max_element( cnts.begin(), cnts.end() ) << std::endl;
  std::cout << "連続40回以上の失敗に出会う確率 = " << 
    std::count_if( cnts.begin(), cnts.end(), [](int x) { return (x > 40); } ) / (double)cnts.size() * 100.0 << "%" << std::endl;
}

結果は

成功回数         = 922 / 10000
平均施行回数     = 9.83406
31回以上連続失敗 = 50
41回以上連続失敗 = 20
51回以上連続失敗 = 8
61回以上連続失敗 = 3
71回以上連続失敗 = 0
最大連続失敗回数 = 70
連続41回以上の失敗に出会う確率 = 2.1692%

成功回数         = 883 / 10000
平均施行回数     = 10.3001
31回以上連続失敗 = 50
41回以上連続失敗 = 22
51回以上連続失敗 = 7
61回以上連続失敗 = 1
71回以上連続失敗 = 1
最大連続失敗回数 = 81
連続41回以上の失敗に出会う確率 = 2.49151%

成功回数         = 884 / 10000
平均施行回数     = 10.3032
31回以上連続失敗 = 60
41回以上連続失敗 = 27
51回以上連続失敗 = 11
61回以上連続失敗 = 5
71回以上連続失敗 = 2
最大連続失敗回数 = 84
連続41回以上の失敗に出会う確率 = 3.0543%


成功回数         = 881 / 10000
平均施行回数     = 10.3507
31回以上連続失敗 = 55
41回以上連続失敗 = 20
51回以上連続失敗 = 11
61回以上連続失敗 = 4
71回以上連続失敗 = 1
最大連続失敗回数 = 75
連続41回以上の失敗に出会う確率 = 2.27015%

成功回数         = 934 / 10000
平均施行回数     = 9.67024
31回以上連続失敗 = 46
41回以上連続失敗 = 20
51回以上連続失敗 = 5
61回以上連続失敗 = 0
71回以上連続失敗 = 0
最大連続失敗回数 = 57
連続41回以上の失敗に出会う確率 = 2.14133%

成功回数         = 947 / 10000
平均施行回数     = 9.55649
31回以上連続失敗 = 44
41回以上連続失敗 = 21
51回以上連続失敗 = 11
61回以上連続失敗 = 4
71回以上連続失敗 = 0
最大連続失敗回数 = 70
連続41回以上の失敗に出会う確率 = 2.21753%

ひどいケースは無くはないけど、プレイしていると、これよりは頻繁に40回以上連続失敗に遭遇していると思う。
また、思ったよりも連続失敗する事が多いのだなと思った。
しょっちゅう連続失敗でマッカが無くなるので、連続失敗の上限を設けてほしいです。
ユーザは、この仕様にかなりやる気を削がれていると思います

2022/1/10 追記: よくみたら、0-10じゃなくて、0-9で計算しないとあきませんやん。こうやって考えると d2の烙印の実装、バグっぽくありません?

2021年12月25日土曜日

tp-link の無線LANルータに固定IPの機器を接続する忘備録

tp-link の無線LANルータにプリンタをLAN接続しようと思ったら、予想外の仕様で時間と取られたので、その忘備録。
ネットワークの知識がないと、かなり辛い。
プリンタに 192.168.1.253/255.255.255.0 のIPv4アドレスを設定し、無線LANルータとLAN接続したが、通信がうまくいかない。
grayhole:~ user$ ping 192.168.1.253
PING 192.168.1.253 (192.168.1.253): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
^C
まず、下記画面のようにプリンタに設定したIPアドレスが、IPアドレス プールの範囲内に存在しないと、繋がらない変テコ仕様。
このままでは、無線LANルータのDHCPサーバにより、192.168.1.253が他の機器に割り当てられてしまう可能性があるので、上図のアドレス予約に192.168.1.253を追加しなければならない。
次のコマンド(arp -a)を実行します。
grayhole:~ user$ arp -a
...
? (192.168.1.1) at b0:a7:b9:62:9e:e0 on en0 ifscope [ethernet]
? (192.168.1.123) at 0:92:21:33:2d:91 on en0 ifscope [ethernet]
? (192.168.1.132) at a4:5e:32:2f:7f:20 on en0 ifscope [ethernet]
? (192.168.1.221) at 1a:32:ad:33:6e:33 on en0 ifscope permanent [ethernet]
? (192.168.1.253) at 8:0:37:cf:8e:26 on en0 ifscope [ethernet]
? (192.168.1.255) at ff:ff:ff:ff:ff:ff on en0 ifscope [ethernet]
...
broadcasthost (255.255.255.255) at ff:ff:ff:ff:ff:ff on en0 ifscope [ethernet]
gr
192.168.1.253 の行に着目し、8:0:37:cf:83:26 がMACアドレスというやつなので、2桁づつの数字 08:00:37:cf:83:26に置き換えて、アドレス予約に追加します。
以上

2021年12月15日水曜日

android darkmode の theme でハマった忘備録

layout.xml において、テキスト色や背景色は、darkmode のテーマに沿って変更されるので問題無いのですが、リストのアイテムが選択された時の挙動をカスタマイズしている所で、罠におちました。
こんなセレクター list_item_color.xml を用意して
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

  <item android:state_pressed="true"  android:drawable="@color/press" />
  
  <item android:state_checked="true"  android:drawable="@color/check" />

  <item android:state_selected="true" android:drawable="@color/white" />

  <item android:state_focused="true"  android:drawable="@color/red" />
  
  <item android:drawable="@color/black" />
 </selector>
リストアイテムとして foo_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<com.example.Util.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/list_item_color"
    android:orientation="horizontal" >

    <CheckBox
        android:id="@+id/pnt_check"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:paddingRight="5dp"
        android:text="@string/foo_name" />

    <TextView
        android:id="@+id/id_value"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="5dp"
        android:layout_weight="1"
        android:gravity="center_vertical"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <ImageView
        android:id="@+id/detail_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_margin="5dp"
        android:focusable="false"
        android:src="@drawable/ic_action_right_dark" />

</com.example.Util.CheckableLinearLayout>
としていました。
ところが、リスト項目の背景に list_item_color.xml の item android:drawable の色 @color/black が使用され、
フォント色は何も指定していないけど、CheckableLinearLayout で制御されているためか、@color/black が使用されてしまいました。
これでは、黒背景に黒文字のため、画面が真っ黒で何も見えません。
リストを選択をすると、背景が違う色になるため、かろうじて黒文字が見える状態です。
list_item_color.xml は、テーマの影響を受けません。
よって、背景色は item android:drawable 固定です。よって正解は、
<?xml version="1.0" encoding="utf-8"?>
<com.example.Util.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/list_item_color"
    android:orientation="horizontal" >

    <CheckBox
        android:id="@+id/pnt_check"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:paddingRight="5dp"
        android:buttonTint="@color/white"
        android:textColor="@color/white"
        android:text="@string/foo_name" />

    <TextView
        android:id="@+id/id_value"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="5dp"
        android:layout_weight="1"
        android:gravity="center_vertical"
        android:textColor="@color/white"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <ImageView
        android:id="@+id/detail_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_margin="5dp"
        android:focusable="false"
        android:src="@drawable/ic_action_right" />
    <!--
        _theme を指定すべきではない。
        android:src="@drawable/ic_action_right_dark" />
-->

</com.example.Util.CheckableLinearLayout>
と、チェックボックスの色と、テキスト色を固定で指定する事でした。
また、@drawable/ic_action_right_dark は darkmode の色なので、_dark を除いた @drawable/ic_action_right にすべきでした。
ただし、ここでは背景色が黒固定なので @color/white を指定すべきかもしれません。

2021年12月6日月曜日

WixFirewallExtension 忘備録

Windows Install Wix で Firewall を追加しようとした時に、いろいろ躓いたので忘備録

コマンドラインからでも、以下のようにすればFirewallを制御できるので
netsh advfirewall firewall add rule name="test" dir="in" action="allow" program="c:\Proguram Files\Foo\x.exe" description="test description" enable="yes" profile="any"
カスタム・アクションを定義してやれば、要件はクリアしそうである。
<CustomAction Id="CA_01_BYPASSFIREWALL" ExeCommand='netsh advfirewall firewall add ...' Directory="Foo" Execute="deferred" Impersonate="no" Return="check" />
<CustomAction Id="CA_02_REMOVEFIREWALL" ExeCommand='netsh advfirewall firewall del ...' Directory="Foo" Execute="deferred" Impersonate="no" Return="check" />
<InstallExecuteSequence>
  <Custom Action="CA_02_REMOVEFIREWALL" Before="InstallFinalize">REMOVE="ALL"</Custom>
  <Custom Action="CA_01_BYPASSFIREWALL" Before="InstallFinalize">not (REMOVE="ALL")</Custom>
</InstallExecuteSequence>
上記は試してません

WixFirewallExtension を使用すると、ファイヤーウォールを制御できます。
プロジェクトのソリューション・エクスプローラのReferencesを右クリックして、「参照の追加」を選択し、Program Files\Wix Toolset v3.11\bin\WixFirewallExtension.dll を追加します。
Product.wxsに FirewallExtension の namespace を追加します。
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:fw="http://schemas.microsoft.com/wix/FirewallExtension">
x64 のコンポーネントだと FirewallExtension が x86 コンポーネントのため、怒られてしまいます。
そのため、x86 のプログラム・フォルダにFirewallのコンポーネントを追加します。
      <Directory Id="ProgramFilesFolder" Name="ProgramFiles86Folder">
        <!-- Firewall -->
        <Component Id="grpcFirewallException" Guid="2B6866D0-0F1F-4579-84A7-87CDE9F57640" KeyPath="yes">
          <fw:FirewallException Id="anyFirewallException" Program="[INSTALLFOLDER]x.exe" Description="BYPASS:x.exe network port" Name="Foo Firewall Exception" Scope="any" />
        </Component>
      </Directory>
      
      
      ...
      <Fragment>
        <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
          ...
          <ComponentRef Id="anyFirewallException"/>
        </ComponentGroup>
      </Fragment>
としてやればOKです。