2022年1月24日月曜日

Vcpkg autolink を無効にする忘備録

vcpkg で、AutoLinkが有効になっている、明後日の方向のライブラリにリンクしてしまい、不可解なエラーに悩まされます。

なので、AutoLink を無効にしたい。

*.vcxprj を開きます。
PropertyGroup を検索し、以下の設定を追加します。
  <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='UnicodeRelease|x64'">
    <VcpkgAutoLink>false</VcpkgAutoLink>
  </PropertyGroup>
  <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='UnicodeRelease|Win32'">
    <VcpkgAutoLink>false</VcpkgAutoLink>
  </PropertyGroup>

UnicodeRelease|x64 等は、自分のビルド構成と合わせるようにしましょう。
以上。

vcpkg BuildTool を古いバージョンに変更備忘録

書いておかないと、忘れて調べ直す事になるので・・・
vcpkg でビルドをすると 最新バージョンのVisual Studio が使用されるようになって、それでは困る場合があるので、その設定の仕方。

vcpkg/triplets ディレクトリ下のファイルに
arm64-windows.cmake
arm-uwp.cmake
x64-linux.cmake
x64-osx.cmake
x64-uwp.cmake
x64-windows.cmake
x64-windows-static.cmake
x86-windows.cmake
とファイルが並んでいます。
その x64-windwos.cmake と x86-windows.cmake に対して
set(VCPKG_TARGET_ARCHITECTURE x64)
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE dynamic)
set(VCPKG_PLATFORM_TOOLSET "v140")
set(VCPKG_DEP_INFO_OVERRIDE_VARS "v140")
というように VCPKG_PLATFORM_TOOLSET, VCPKG_DEP_INFO_OVERRIDE_VARS を追加し、TOOLSET のバージョンを指定します。
以上。

なんか、一時的にブロガーのポストができなくなって、前のポストを一旦削除して、作り直しました。

C++データを16進表記相互変換

ちょくちょくデータを暗号化して16進数表記文字列に変換して保存し、保存された16進表記文字列をデータに復元する事をやるので、忘備録として記録する事に。こういう、ちょっとしたものでも、書こうと思ったら時間を取られる。
#include <string>
#include <iostream>

static int atob( int c ) {
  static const unsigned char btbl[] = {
    // 0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  0
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  1
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  2
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05,  0x06, 0x07,  0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  3
    0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,  0x0F, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  4
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  5
    0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,  0x0F, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  6
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  7
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  8
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  9
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  A
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  B
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  C
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  D
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  E
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   //  F
  };
  return btbl[ c ];
}


//! 16進文字列から unsigned char 配列への変換
/*
  @note 16進文字列は、0-9, A-F のみを利用した表記で
    1バイトを2文字で表記しているものとする。16進を示す 0x 等の
    接頭辞は含まれていない。
*/
void hexstr2str(
  const std::string& src,
  std::string& dst
) {
  dst.resize( (src.size() + 1) / 2 );
  for(size_t i = 0; i < src.size(); i++) {
    if( (i & 1) != 0 ) {
      dst[ i / 2 ] |= atob( src[i] );
    } else {
      dst[ i / 2 ] = atob( src[i] ) << 4;
    }
  }
}

//! unsigned char 配列から 16進文字列への変換
/*!
  @note 16進文字列は、0-9, A-F のみを利用した表記で
    1バイトを2文字で表記したものに変換される。16進を示す 0x 等の
    接頭辞は含まない。
*/
void str2hexstr(
  const std::string&  src,
  std::string&        dst
) {
  static const char atbl[] = {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
  };
  dst.resize( src.size() * 2 );
  for( size_t i = 0; i < src.size(); i++ ) {
    dst[i*2  ] = atbl[ ((src[i] >> 4) & 0x0F) ]; // & 0x0F しないと算術シフトでアウトでした
    dst[i*2+1] = atbl[ (src[i] & 0x0F) ];
  }
}

int main() {
  std::string src = "Hello world!";
  std::string hex, dst;
  std::cout << src << std::endl;
  str2hexstr( src, hex );
  std::cout << hex << std::endl;
  hexstr2str( hex, dst );
  std::cout << dst << std::endl;
  return 0;
}

結果

Hello world!
48656C6C6F20776F726C6421
Hello world!
2022/01/14 追記: str2hexstr のコメントに書いたバグ修正をしました

2022年1月7日金曜日

JNI GetMethodID に指定するタイプ文字列 忘備録

JNI で Java method id を取得する GetMethodID 関数に渡す文字列のドキュメントが見つからないので、忘備録として記す事に

まず、Primitive Type の表

タイプ文字列Primitive Type
V void
Z boolean
B byte
C char
S short
I int
J long
F float
D double


クラスのタイプ文字列は、
 Ljava/lang/String;
というように L で始まり、class URIを書いて ; で閉じる

配列の場合は、
 [I
というように [ で始まり、タイプ文字列を書く
上記の場合 int [] に対応する

関数表記は
()V
([Ljava/lang/String;)I
というように、 ( 引数 ) 返り値 というように表記する
以上

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 を指定すべきかもしれません。