ASUS TransBook T101HA-G128 BIOSパスワードのリセット方法

 昨夜、寝床でPCを使用していた。先日購入したASUSの2 in 1ノート、「TransBook T101HA-G128」だ。夜中のこととて、イヤホンを挿入した。ところが、「オーディオ機器が接続されました」とのメッセージは表示されるのに、音が出ない。

 前のTransBook(T100Chi)では、タッチパネルが動かなくなることが多く、そういうときはBIOSのデフォルトをロードしなおして再立ち上げすると直った。時計が遅れる現象などもこれで直ったものだ。

 このPCもそうだろう、同じようにすれば直るのでは、と思い、BIOSセットアップ画面を出した。T100Chiと比べて、T101HAはキーボードがBluetoothではなく、物理接続なので簡単だ。電源投入直後、「ASUS」ロゴの表示画面で[F2]キーを押し下げながら起動すると、BIOSセットアップ画面が表示される。

 BIOSセットアップに入るためのパスワード画面が出る。一昨日、他人に悪用されることがないようにとBIOSパスワードをセットしておいたのだ。Administrator・User両方ともである。

 得たり、とセットしておいたAdministratorのパスワードを入力する。

 「Invalid Password」とはじかれる。あれ?慎重にもう1回……あれ?もう2回……

 パスワードは3回はじかれて、画面がフリーズした。

 電源を入れなおしては数回試みるが、同じである。

 幸いにUserパスワードのほうは正しくセットされていなかったらしく、無入力+EnterでBIOS画面だけは出すことができた。だが、Administratorではないので、デフォルト値ロードなどの肝心の選択肢が使えない。

 うーむ。参った……。

 ……と、いうようなわけで、ネットを渉猟し、「ASUS TransBook T101HA-G128」の「BIOSパスワードリセット方法」が分かった。

 検索して出てくる方法は、少し情報が古かったりするようなので、私が実行してうまくいった最新の方法をここに書き留めておきたい。多分、私と同じようなハメに(おちい)った人が、検索して役立てるだろう。

「ASUS TransBook T101HA-G128」のBIOSパスワードリセット方法
  1.  PCの日付を「2011年11月23日」にする。
  2.  ネットのほかの情報では「2002年1月2日にする」と書かれているものがあるが、私の環境ではなぜかうまくいかなかった。おそらく機種や発売時期で異なるのだと思われる。

  3.  再起動し、ASUSロゴ表示前に[F2]キーを長押し等する。長押しでうまくいかない場合は、間欠的に指を離してまた押す等するとよい。
  4.  パスワード入力画面が表示される。
  5.  なんでもいいので、何か文字を入力し、一旦Enterする。「Invalid Password」となる。Enterキーを押す。
  6.  (おもむろ)に [Alt] + R を入力する。(←重要!)
  7.  画面に「Enter Rescue password / 2011/11/23」と表示される。
  8.  「A1AAABBA」とパスワードを入力する。この際、シフトキー等を使用しない。
  9.   BIOSのAdministratorパスワードが解除された状態でBIOSセットアップが起動する。

 これで無事、自分のPCの支配権がすべて自分に戻ってくるのであった。めでたしめでたし。

その他の補足情報

 実は上記に行き着くまでに、ほかの方法もいろいろと試した。結局あまり意味はなかったが、副産物として後々参考になりそうな事項があったので、以下に書いておく。

BIOS等のバイナリファイルの16進及びASCIIダンプの取り方

 昔は「dump」などのコマンドがMS-DOSの拡張キットなどに入っていたと記憶するが、Windows 10のコマンドラインツールにはない。

 しかし、代替手段はある。証明書関連の諸作業に使用するコマンドの「certutil.exe」を使えばダンプをとることができる。

 例えば下記は、そのcertutil.exeを使用し、ASUSのサイトからダウンロードした本日現在最新のBIOSのダンプをとっているところである。

C:\>certutil -f -encodehex C:\T101HAAS.304 C:\T101HAAS.304.dmp
入力長 = 6293504
出力長 = 29824512
CertUtil: -encodehex コマンドは正常に完了しました。

 こうすると、「C:\T101HAAS.304.dmp」にテキストでダンプが取れるから、それを見て解析するとよい。注意すべき点は、バイナリ形式の中での文字列は、一文字ごとに0x00が入ったりすることなので、「ALAA」という文字列を探す場合は、「A.L.A.」……というふうに探さないと見つからない。また、改行も入るから、文字列を当てにしての検索はあまりうまくいかないと思ったほうがよい。

ASUS「WinFlash」で無理やりBIOSを書き換える方法

 実はBIOSを強制的に上書きすれば、BIOSのAdministratorパスワードもリセットされるのではないか、と思ったのだ。結果は「リセットされなかった」ので、無駄であった。ネットのQ&Aなどで「BIOSをアップデートすればパスワードもリセットされますよ」などという解答があったのだが、これは誤りとみてよい。また、機種等にもよるのであろう。

 だが、何か他のことで、BIOSを無理やり上書きしたいという人もいるかもしれないと思うので、その情報を書いておく。

 標記「WinFlash」はASUS純正のBIOSアップデートユーティリティだ。安全にできており、日付などでうまく制御され、無駄なダウングレードなどはできない仕組みになっている。

 しかし、コマンドラインオプションをつけて起動することで、強制的に書き換えたり、日付を無視してダウングレードなどすることができる。

 ネットでは「/nodate」オプションが第三者によって紹介されているが、このプログラムのダンプをとると、次のようなコマンドラインオプションがあることがわかる。

/nodate ダウングレード等のため、タイムスタンプを無視する。
/force 強制的に書き換え
/nowmsg 不明(メッセージの抑制ではないかと思われる)
/nodefault 不明

 私は上のうち、「nodate」と「force」の両方を試し、特にシステムが破壊される等の支障はなかった。BIOSはきれいに上書きされた。……パスワードは初期化されなかったので、意味はなかったが(苦笑)

 しかし、意味もなく上記のオプションをつけてWinFlash.exeを実行し、PCがおかしくなったとしても、私の知ったことではない。

cmospwd

 他に、「cmospwd」というフリーソフトを使ってCMOSをフラッシュする、という情報がネットに多く見つかるが、どうもASUS TransBook T101HA-G128には適合しないらしく、うまくいかない。「ioperm」というシステムのインストールを求められるのだが、それがうまくいかない。

他のパスワード

 ASUSのBIOSパスワードに関することはネットに情報があり、PCに設定する日付ごとにパスワードが変化するようである。

 実際に入力して試してはいないが、次のような情報がある。

日付 パスワード
2011-11-23 A1AAABBA
2011-11-24 AL11LAAA
2011-11-25 ADH0AHBB
2011-11-26 AAAAB1BL
2011-11-27 A9BOCAAD
2011-11-28 A0B0ADBD
2011-11-29 AADD0L2B
2011-11-30 L1DDO1AB
2011-12-01 0DADBALA
2011-12-02 LA9AC0BA
2011-12-03 L9L1ACAA
2011-12-04 B0L00ALA
2011-12-05 BBAAAA0B
2011-12-06 2ABOHBAL
2011-12-07 2OA0BALD
2011-12-08 1BADLL0D
2011-12-09 1H9A2BAB
2011-12-10 B9BA0BDB
2011-12-11 BBB1AAL0
2011-12-12 OBDH4LAL
2011-12-13 OAAABBDB
2011-12-14 AO2OLBL2
2011-12-15 AB40BAA1
2011-12-16 A4ADAHD1
2011-12-17 AABAO1LC
2011-12-18 AAB1AAA9
2011-12-19 A1DHDBDB
2011-12-20 AADHLHBA
2011-12-21 AOAAB1AA
2011-12-22 AL1BAADA
2011-12-23 A4HB0BBA
2011-12-24 AAADALAA
2011-12-25 AAOADABB
2011-12-26 A2021BBL
2011-12-27 B0D4ALAD
2011-12-28 BLAAB9BD
2011-12-29 LA1BAA2B
2011-12-30 BACBOBAB
2011-12-31 AAOLDOA0

WordPress+Jetpackパブリサイズ共有のカスタマイズ

 WordPressとFacebookを併用するとき、有名プラグイン「Jetpack」の「バブリサイズ共有」機能を使うのは、常道中の常道である。

 私も愛用している。

 しかし、FBにクロスポストする際、記事の全文が引用されてしまうなど、いろいろと問題も多いことは指摘している人も多い。

 この「全文引用問題」については、「全文引用させないコツ」などを発表している方も多く、ネットに情報はたくさんある。

 ところが、私の場合、「別に全文引用されてもかまわない」のである。ただ、不満点は、「改行をサニタイズしないでほしい」ということなのだ。これをやられると、ホンット、FBのウォールが鬱陶しいものになってしまう。どうせ全文引用するなら、段落などもちゃんと引用してほしいのだ。

 そこで、プラグインのソースコードを覗き見る。

 「jetpack/modules/publicize.php」というのがパブリサイズ共有の機能部分で、その中に次のような個所がある。

public static function sanitize_message( $message ) {
	$message = preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $message );
	$message = wp_kses( $message, array() );
	$message = preg_replace('/[\r\n\t ]+/', ' ', $message);
	$message = trim( $message );
	$message = htmlspecialchars_decode( $message, ENT_QUOTES );
	return $message;
}

 赤字の部分で空白とタブ、改行をサニタイズしているようだ。そこでこれをコメントアウトしてみた。

public static function sanitize_message( $message ) {
	$message = preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $message );
	$message = wp_kses( $message, array() );
//	$message = preg_replace('/[\r\n\t ]+/', ' ', $message);
	$message = trim( $message );
	$message = htmlspecialchars_decode( $message, ENT_QUOTES );
	return $message;
}

 ところが、試してみてもやっぱり改行がサニタイズされてしまう。

 それに、こうやって対応することには問題がある。ソースコードをフォークしてしまうと、バージョンアップのたびに同じ個所をカスタマイズしなおすことになるのだ。だが、まあ、バージョンアップなんてそんなに頻繁にないし、こんなくらい、「まあいいや」で済んでしまうということもある。

 いずれにしても、これは引き続き要調査、である。

いよいよ多機能リモコン

 LEDを強力に光らせることが出来たので、いよいよWebサーバつき多機能リモコンを作成する。卓上などに置いておき、ネットワークにつないで、スマホなどから複数の電化製品を操作できるというものだ。

 ここでは、いくつかのテクニックを使った。

 一つは、フォームが大きくなってしまい、ハードコーディングするとメモリが足りなくなる。そこで、SDカード内にHTMLを置き、これを読み出すようにした。

 同様に、リモコンから読み取った数値データが大きくなって、普通にハードコーディングしたのではメモリが不足する。そこで、「PROGMEM」というキーワードを使って、フラッシュメモリ内にデータを置き、これを読み出すようにした。

IMG_3134 ETHERNET SHIELD 2を遺憾なく使う。SDカードを取り付けられるから、そこにHTMLを書き込んでおけばよい。FETをつけたブレッドボードと一緒に、買っておいたSparkfunの基盤に固定する。

 SDカード内には、次のようなHTMLを置き、ファイル名を「irform.htm」とする。

<html>
 <head>
  <meta name="Editor" content="Notepad.exe">
  <meta http-equiv="Content-Type" content="text/html;charset=Shift_JIS">
  <title>Webリモコン</title>
  <basefont size=4>
 </head>

 <body bgcolor="#ddffdd">
  <center>
   <h1><b>Webリモコン</b></h1>
     <table>
      <tr><td> 作成者   </td>
       <td align="right">佐藤俊夫</td></tr>
      <tr><td> 作成日時 </td>
       <td align="right">27.07.19 (日) 1835</td></tr>
     </table>
  </center>
  <hr>
  <center>
    <form method="get" name="irremote">
    <table border=1>
      <tr><th>機器</th><th>ボタン</th></tr>
      <tr>
        <td rowspan=4>扇風機</td>
        <td><input submit type="submit" value="入/風量" name="fan_on"></td>
      </tr>
        <tr><td><input submit type="submit" value="タイマー" name="fan_timer"></td></tr>
        <tr><td><input submit type="submit" value="首振" name="fan_swing"></td></tr>
        <tr><td><input submit type="submit" value="切" name="fan_off"></td></tr>
      </tr>
      <tr>
        <td rowspan=5>テレビ</td>
        <td><input submit type="submit" value="入/切" name="tv_on_off"></td>
      </tr>
        <tr><td><input submit type="submit" value="音量大" name="tv_volup"></td></tr>
        <tr><td><input submit type="submit" value="音量小" name="tv_voldown"></td></tr>
        <tr><td><input submit type="submit" value="チャンネル>" name="tv_chup"></td></tr>
        <tr><td><input submit type="submit" value="チャンネル<" name="tv_chdown"></td></tr>
    </table>
    </form>
  </center>
 </body>
</html>

irform 上のHTMLの見た目はこんな感じだ。

 スケッチは次のようになる。

//
//  Web2IRremote.ino
//    リモコンをウェブで操作する。
//    27.07.25(日) 1930
//    佐藤俊夫
//
#include <SPI.h>
#include <Ethernet2.h>
#include <SD.h>
#include <IRremote.h>
#include <avr/pgmspace.h>
//
byte mac[] = {  0x90, 0xA2, 0xDA, 0x0F, 0xF6, 0x74 };
IPAddress ip(192, 168, 1, 129);
EthernetServer SERVER(80);
EthernetClient CLIENT;
IRsend irsend;
PROGMEM
  const unsigned int
    fan_on[]     = {4500,2150, 600,500, 650,500, 600,500, 600,500, 600,1650, 600,1600, 650,1550, 650,500, 600,1600, 650,1600, 600,1600, 650,450, 600,1600, 650,500, 600,500, 650,500, 600,1600, 600,500, 650,500, 600,500, 600,500, 600,500, 600,1650, 600,500, 600,500, 600,500, 650,1600, 600,1600, 600,1650, 600,1600, 600,500, 650,500, 600,0},
    fan_timer[]  = {4500,2150, 550,550, 550,600, 550,550, 600,500, 550,1700, 500,1700, 550,1650, 550,600, 550,1650, 550,1700, 500,1700, 550,600, 500,1700, 550,550, 550,550, 550,600, 500,1700, 550,600, 500,600, 500,600, 500,600, 550,550, 550,1700, 550,600, 450,600, 550,550, 550,600, 500,1700, 550,1650, 550,1700, 550,1650, 550,600, 500,0},
    fan_swing[]  = {4450,2200, 600,550, 550,500, 600,550, 550,550, 550,1700, 550,1650, 550,1700, 550,550, 550,1650, 550,1700, 550,1650, 550,550, 600,1650, 550,550, 550,550, 550,550, 600,1650, 550,550, 550,550, 600,550, 550,550, 550,550, 600,1600, 600,550, 550,550, 550,1650, 600,1550, 650,1700, 550,1650, 550,550, 550,550, 600,550, 550,0},
    fan_off[]    = {4450,2250, 550,550, 600,550, 550,500, 600,550, 550,1650, 600,1650, 550,1650, 600,550, 550,1650, 550,1650, 600,1650, 550,550, 550,1700, 550,550, 550,550, 550,550, 550,1700, 550,550, 550,550, 550,550, 600,550, 550,550, 550,1650, 550,550, 600,550, 550,1650, 600,1650, 550,550, 550,1700, 550,500, 600,550, 550,1650, 600,0},
    tv_on_off[]  = {3400,1750, 400,500, 350,1350, 400,500, 350,500, 400,500, 350,500, 400,500, 350,450, 400,500, 400,500, 350,500, 400,500, 350,500, 350,1350, 400,500, 400,500, 350,450, 400,500, 400,500, 350,450, 400,500, 400,500, 350,500, 400,1300, 400,500, 400,450, 400,500, 400,500, 350,500, 350,500, 400,450, 400,450, 400,1350, 400,500, 400,1300, 400,1350, 400,1350, 400,1350, 400,450, 400,500, 400,1300, 400,500, 400,1300, 400,1350, 400,1350, 400,1350, 400,500, 350,1350, 400,0},
    tv_volup[]   = {3400,1750, 400,500, 400,1300, 400,500, 400,500, 350,500, 450,400, 400,500, 350,500, 400,500, 350,500, 350,500, 400,500, 350,500, 400,1300, 400,500, 400,450, 400,500, 350,500, 400,500, 350,500, 400,500, 350,500, 350,500, 400,1300, 450,450, 400,500, 350,500, 400,500, 350,500, 400,450, 400,500, 350,500, 400,500, 350,450, 400,500, 400,500, 350,500, 450,1250, 400,500, 400,500, 350,500, 400,450, 400,500, 350,500, 400,500, 350,1350, 400,450, 400,1350, 400,0},
    tv_voldown[] = {3400,1750, 400,500, 350,1350, 400,500, 400,450, 400,500, 350,500, 400,450, 400,500, 400,500, 350,500, 350,500, 400,500, 350,500, 350,1300, 450,500, 400,500, 350,450, 400,500, 450,450, 350,500, 400,450, 400,450, 400,500, 400,1300, 450,500, 350,500, 350,500, 400,500, 350,450, 400,500, 400,500, 350,500, 400,1300, 400,500, 400,450, 400,500, 400,500, 350,1350, 400,500, 350,500, 400,1300, 400,500, 400,500, 350,500, 350,500, 400,1300, 450,500, 350,1350, 400,0},
    tv_chup[]    = {3400,1750, 400,500, 400,1350, 450,400, 400,450, 400,500, 450,400, 400,450, 400,500, 450,450, 450,400, 450,450, 400,400, 400,500, 450,1250, 450,500, 350,450, 500,400, 450,400, 400,500, 350,500, 450,450, 350,500, 450,450, 450,1250, 400,500, 450,400, 400,500, 400,450, 450,400, 450,450, 350,500, 450,400, 450,450, 350,500, 450,1250, 400,500, 450,1250, 500,1250, 500,400, 450,450, 350,500, 450,450, 350,1350, 450,450, 400,1300, 450,1250, 500,450, 400,1250, 450,0},
    tv_chdown[]  = {3500,1650, 450,500, 400,1300, 400,500, 450,400, 350,500, 400,450, 500,400, 450,450, 350,450, 400,500, 400,500, 350,500, 400,450, 450,1300, 450,450, 350,450, 450,500, 350,500, 450,400, 450,400, 400,500, 350,500, 450,400, 400,1350, 450,400, 500,400, 450,450, 450,400, 400,500, 350,500, 350,500, 400,500, 350,1350, 450,450, 350,1350, 400,500, 350,1350, 500,1250, 450,450, 450,400, 450,1250, 500,400, 450,1300, 450,450, 400,1300, 450,1250, 450,500, 350,1350, 450,0};
////
void setup() 
{ 
  const int chipSelect = 4;
  Ethernet.begin(mac, ip);
  SERVER.begin();
  if (!SD.begin(chipSelect)) {
    return;
  }
} 
 
void loop() 
{ 
  //  Webサーバの動作
  char c;
  String rstr = "";
  CLIENT = SERVER.available();
  if (CLIENT) {
    while (CLIENT.connected()) {
      if (CLIENT.available()) {
        c = CLIENT.read();
        rstr += c;
        if(rstr.endsWith("\r\n")){
          break;
        }
      }
    }
    if(rstr.indexOf("fan_on=") >= 0){
      unsigned int buf[sizeof(fan_on) / sizeof(*fan_on)];
      for(int i = 0; i < sizeof(fan_on) / sizeof(*fan_on); i++){
        buf[i] = pgm_read_word(fan_on + i);
      }
      irsend.sendRaw(buf, sizeof(buf) / sizeof(buf[0]), 38);
    }
    else if(rstr.indexOf("fan_timer=") >= 0){
      unsigned int buf[sizeof(fan_timer) / sizeof(*fan_timer)];
      for(int i = 0; i < sizeof(fan_timer) / sizeof(*fan_timer); i++){
        buf[i] = pgm_read_word(fan_timer + i);
      }
      irsend.sendRaw(buf, sizeof(buf) / sizeof(buf[0]), 38);
    }
    else if(rstr.indexOf("fan_swing=") >= 0){
      unsigned int buf[sizeof(fan_swing) / sizeof(*fan_swing)];
      for(int i = 0; i < sizeof(fan_swing) / sizeof(*fan_swing); i++){
        buf[i] = pgm_read_word(fan_swing + i);
      }
      irsend.sendRaw(buf, sizeof(buf) / sizeof(buf[0]), 38);
    }
    else if(rstr.indexOf("fan_off=") >= 0){
     unsigned int buf[sizeof(fan_off) / sizeof(*fan_off)];
     for(int i = 0; i < sizeof(fan_off) / sizeof(*fan_off); i++){
        buf[i] = pgm_read_word(fan_off + i);
      }
      irsend.sendRaw(buf, sizeof(buf) / sizeof(buf[0]), 38);
    }
    else if(rstr.indexOf("tv_on_off=") >= 0){
     unsigned int buf[sizeof(tv_on_off) / sizeof(*tv_on_off)];
     for(int i = 0; i < sizeof(tv_on_off) / sizeof(*tv_on_off); i++){
        buf[i] = pgm_read_word(tv_on_off + i);
      }
      irsend.sendRaw(buf, sizeof(buf) / sizeof(buf[0]), 38);
    }
    else if(rstr.indexOf("tv_volup=") >= 0){
     unsigned int buf[sizeof(tv_volup) / sizeof(*tv_volup)];
     for(int i = 0; i < sizeof(tv_volup) / sizeof(*tv_volup); i++){
        buf[i] = pgm_read_word(tv_volup + i);
      }
      irsend.sendRaw(buf, sizeof(buf) / sizeof(buf[0]), 38);
    }
    else if(rstr.indexOf("tv_voldown=") >= 0){
     unsigned int buf[sizeof(tv_voldown) / sizeof(*tv_voldown)];
     for(int i = 0; i < sizeof(tv_voldown) / sizeof(*tv_voldown); i++){
        buf[i] = pgm_read_word(tv_voldown + i);
      }
      irsend.sendRaw(buf, sizeof(buf) / sizeof(buf[0]), 38);
    }
    else if(rstr.indexOf("tv_chup=") >= 0){
     unsigned int buf[sizeof(tv_chup) / sizeof(*tv_chup)];
     for(int i = 0; i < sizeof(tv_chup) / sizeof(*tv_chup); i++){
        buf[i] = pgm_read_word(tv_chup + i);
      }
      irsend.sendRaw(buf, sizeof(buf) / sizeof(buf[0]), 38);
    }
    else if(rstr.indexOf("tv_chdown=") >= 0){
     unsigned int buf[sizeof(tv_chdown) / sizeof(*tv_chdown)];
     for(int i = 0; i < sizeof(tv_chdown) / sizeof(*tv_chdown); i++){
        buf[i] = pgm_read_word(tv_chdown + i);
      }
      irsend.sendRaw(buf, sizeof(buf) / sizeof(buf[0]), 38);
    }
    rstr = "";
    sendform();
    delay(1);
    // close the connection:
    CLIENT.stop();
  }
  delay(20);
}
void sendform(){
  //  フォームを送る。
  CLIENT.println("HTTP/1.1 200 OK");
  CLIENT.println("Content-Type: text/html");
  CLIENT.println("Connection: close");
  CLIENT.println();
  CLIENT.println("<!DOCTYPE HTML>");
  File html = SD.open("irform.htm");
  if (html) {
    while (html.available()) {
      CLIENT.write(html.read());
    }
    html.close();
  } 
}

IMG_3135 勿論、ただのWebであるから、このようにスマホの他、タブレットなどからも操作可能である。また、ルータでポートフォワードすれば、外出先からの操作も可能である。

1億倍で言わないと消滅する。

 以前、「中国人13億人と日本人1億3千万とが全力で殺し合いをしたら、秒殺で日本人全滅。戦い方で工夫をして勝つなら、あらゆる能力が100倍優れてないとダメ」みたいなことを、ランチェスターの二次則にからめて書いた。

 簡単な理屈で、100倍というのは勢力比の自乗である。

 もう一度書くならこういうことだ。ランチェスターの2次則によれば、損耗は勢力比の自乗で作用する。

{B_0}^2 - {B_t}^2 = E({R_0}^2 - {R_t}^2)

 ここに、
  B 青軍
  R 赤軍
  B0、R0:  青・赤両軍の最初の兵力
  Bt、Rt:  ある同じ時点での青・赤両軍の残存兵力
  E:  兵力の質の比。赤軍の質が青の倍であれば2、半分であれば0.5。

 式を変形すると、例えば、

{B_t = \sqrt{{B_0}^2 - E({R_0}^2 - {R_t}^2)}}

 このR0に日本の人口、Rtにはゼロを、B0に中国の人口、Eに1.0を代入すれば、つまり「日本人が全滅を期して捨て身の特別攻撃をしかけて、中国にどれだけの損耗を強いることができるか」という冷厳な計算となる。

 言うまでもないが、この計算はするだけムダだ。それでもあえて計算してグラフを描けば、こうなる。

Photo_3

 日本人の人数の、10分の1の損耗すら、与えることが出来ない。一人十殺どころか、10人がかりで1人殺すこともできないのである。

 これを互角にするには、兵力の質の比「E」を高めることだが、これも計算するだけムダである。100倍以上という数字が出るだけだ。

E=\cfrac{{B_0}^2 - {B_t}^2}{{R_0}^2 - {R_t}^2}

 この式にそれぞれ中国と日本の人口、互角となるようにBtとRtにゼロを代入すれば、約106という途方もない数字になってしまう。

 これが、先日私が書いた、じつにお粗末で簡単な理屈である。だがしかし、「殺し合い」なぞと物騒な書き方をしたから、どうにも老幼婦女子に刺激が強すぎたと言おうか、まず「穏当でなかった…」のは否めない。

 だが、殺し合いまでは行かない、例えばあることに関する意見や主張、ということではどうだろう。

 「昭和10年~20年(1935年~1945年)までをリアルに過ごした全ての日本人は悪魔で殺人鬼で血も涙もない許すべからざる鬼畜で、レイプ大好きな人類の敵だった」

…ということを、13億人の中国人が全員で言い、そして、かたやの日本人の、まあ、せいぜい100万人ほどのかわいい勢力が、小さな声で

「そ、そんなことないよぉ…当時の日本人にだって、いい人はたくさんいたんだよぉ…」

と、ボソボソ口ごもるとする。まあ、大声の大合唱と、小さな声のつぶやきとの戦いだ。そうすると、どうなるのだろう。

 この際、10億ナンボという土台に対して、朝鮮半島の5、6千万なぞ、計算の埒外、誤差というか、ゴミのようなものであることをあらかじめ言っておく。

 13億人の中国人全員が全力で100%の力を出し切ってこんなことを言うというのも、非現実的だ。中国人の中にだって、「いやいや、それは言い過ぎだって。日本だって、当時当時の情勢ってものもあったわけだから」と、一定の理解を示す知性のある人も少なからずいるだろう。だから、方程式の入力に「13億」と叩き込むのはよろしくない。また、全員が100%で主張するというわけでもなく、かなりラジカルな活動家でも、1%ぐらい「日本人だって人間なんだから」と心の片隅で思っていなくもないだろう。そういったところをあれこれ差し引きして、

「13億人中の10億人が全力で『A』と主張する」

…とでもしようではないか。

そして対する日本が、「100万人のかわいい勢力が小さな声で言う」というところを置き換えて

「10万人の勢力が全力で『非A』と主張する」

とでもしようではないか。

 先日の私の遊びのように、13億対1億3千万をランチェスターの二次則に代入するなど、代入する前からわかりきった馬鹿馬鹿しいことだった。それが10億対10万である。これは馬鹿馬鹿しいを通り越して頭脳の目方を疑われるような無意味なことだ。

 それでも、あえてグラフを描こう。

Photo_4

 横軸の、中国の10億が、まったく変化していないことに注目しよう。実は変化しているのだが、桁が小さすぎて表示できないのだ。つまり、ただの一人たりと、日本の意見に同意してもらうことなど出来ない。

 では、これを互角にするにはどうしたらよいのだろう。互角にするためには、交換比Eを計算すればよい。

E=\cfrac{{B_0}^2-{B_t}^2}{{R_0}^2-{R_t}^2}=\cfrac{10^2}{0.001^2}=\cfrac{100}{0.000001}=100000000

 1億倍である。

 こちらの主張を、日本人特有のおくゆかしさでもって、「いつかはどちらが正しいかをちゃんと天が見定めてくれる」とわけしりぶって小さな声で言っていることには、数値上の意味はまったくない、ということだ。

 正しいとか、正しくないとかはこの際置こう。おじいちゃんおばあちゃん、ひいおじいちゃんひいおばあちゃん、我々を産み育てた父祖の世代が、「クズでカスで大便みたいなゴミだった」という認定が、世界的定説になるかならないか、それをどうするのかということなのだ。

 それを互角に保つには、キチガイ右翼の街宣車のボリュームがやかましいなどという、そんなどころの騒ぎではまったくダメで、「1億倍の強度でそれを言わなければならない」ということである。

 「1億倍の強度で言う」ということは、簡単なことではない。これは例えではないからだ。

 例えではない、ということはどういうことか。具体的に書けば、中国人一人がネットに

「日本カス。死ね。」

…と8文字ほど書いたら、互角に対抗するために、10万人の日本側は

「日本はよい国です日本はよい国です日本はよい国です日本はよい国です日本はよい国です日本はよい国です日本はよい国です日本はよい国です

~(中略)~

日本はよい国です日本はよい国です日本はよい国です日本はよい国です日本はよい国です日本はよい国です日本はよい国です日本はよい国です」

…と、8億文字ほどの情報をネットに流せ、ということなのだ。そうしないと、「日本人は昔から罪深い糞でアホでカスだった」という認定が、朝夕に迫るのである。

 そんなことは、到底できることではない。

プログラミング言語「R」で遊ぶ

 プログラミング言語「R」というものを知る。

 恥ずかしながら不肖この佐藤、これまで数多くのプログラミング言語を扱ってきたし、10種やそこらはゆうに越える種類のプログラミング言語で実用にかなうプログラムを書き、実際に使用もしてきた。また自らプログラミングしたことがないいろいろな種類の言語でも、その名前や特性、出所来歴は知っている。…つもりでいた。

 迂闊であった。

 この「R」という言語など、まったく全然、少しもちっとも、知らなかった。知ったのは一昨日である。

 なぜ知ったのかというと、マルコフ決定について学ばなければならず、それにはマルコフ連鎖をわきまえなければならない。マルコフ連鎖について書かれたサイトを渉猟していると、「ここをRで説明すると…」などとして説明しているサイトに行き当たった。ナニ、Rで説明だと!?Rて何だ?知らん。聞いたことがない。

 さてそういうわけで、さっそくRのバイナリをダウンロードしてインストールし、試す。オープンソースにしてフリーであり、お金はかからない。Linux/Windows/Macと、色々な種類の計算機で動く。Windows用バイナリは次のURLにある。

 Rは統計解析に向く言語で、Rという言語仕様そのものよりも、そのインタプリタ風実行環境――かつてのBASICに似ている――全体を含めて、統計処理がしやすく作られている。コンソールにコマンドを打ち込んでいくだけですぐに結果が得られる。電卓代わりに使うだけでもなかなか便利だ。

 ふと思いついて、このRと、「ランチェスターの2次則」で土曜日の昼下がりを遊んでみようか、という気になる。

 ランチェスターの2次則は、オペレーションズ・リサーチの古典理論として知られている。もともとはイギリスの技術者ランチェスターが、まだ飛行機が戦力として有望でない第一次大戦の時代に、将来飛行機が大量に使用されるときの損耗の推移を考察・研究し、発表した軍事理論である。

 歴史上のさまざまな戦争の戦闘経過をこの公式にあてはめると、まるで嘘じゃないかというほどよく合致するので、オペレーションズ・リサーチの分野でよく知られ、いまなお良く使用されている。日本では企業の競争などのモデルに使われており、これが実は軍事理論であるとは知らない人も多い。

 式は実に簡単だ。

{B_0} ^ 2 - {B_t} ^ 2 = E({R_0} ^ 2 - {R_t} ^ 2)
 ここに、

B : 青軍

R : 赤軍

B_0, R_0 : 青・赤両軍の最初の兵力

B_t, R_t : ある同じ時点での青・赤両軍の残存兵力

E : 兵力の質の比。赤軍の質が青の倍であれば2、半分であれば0.5。

 まことに単純きわまる。何の疑問もない式だ。「E」が1.0のとき、それぞれ全く同じ人数の青、赤両軍が全員で殺し合いをすれば、双方とも等しく損耗し、同時に全滅する。しかし、兵力に差があると、その差に「自乗」が作用し、思っているよりも損耗差が大きく開いていく、という式だ。

 ここで「だから戦争はしてはいかんのだ」と脱線するのもなかなか楽しそうだが、今日は脱線しない(笑)。

 式を変形すると、例えば、

B_t = \sqrt{{B_0}^2 - E({R_0}^2 - {R_t}^2)}

 などという、まことに楽しげな式ができる。ここで、赤軍(R)が劣軍として、R_tにゼロを代入し、B_0R_0に開戦時の兵力を入れれば、赤軍が全滅したときに青軍がどれくらい残っているか、ということが見積もれるのである。また、

E=\cfrac{{B_0}^2 - {B_t}^2}{{R_0}^2 - {R_t}^2}

 とすると、例えば兵力が足りない側が、どれくらい優れた兵器を持たなければならないか、ということが簡単に見積もれる。

 ランチェスターの2次則はほかにもいろいろとイジりがいのある理論で、たとえば「B_t」に関する最初の変形を微分して導関数を出せば、某時点での接線の傾きが求められるから、「傾き1以上」になるときの兵力がいくつか、ということから、「急に敗色が濃厚になってきたのがいつごろか」などというものも計算でき、これがまた、歴史上の色々な戦例に合致したりするから侮れない。

  さて、起動したRのコンソールに、次のように入力する。

> # 関数Bt
> Bt<-function(B0,R0,Rt,E){
+ Bt=sqrt(B0^2-E*(R0^2-Rt^2))
+ Bt
+ }

 これで、ひとつ目の変形、「双方の初期兵力と、赤軍の現在兵力及び双方の兵力の質に応ずる青軍の現在勢力」を求める関数が定義される。
 
 この関数で、実際の勢力の推移を求めよう。Rでは、こんなふうにすると、たちどころに数列が配列に格納される。

> Bts<-Bt(100, 80, 80:0, 1.0)

 これで、劣軍勢力が80から0になるまでの、優軍勢力の推移が配列Btsに格納される。格納された様子を見るには、配列名をタイプするだけでいい。

> Bts
[1] 100.00000 99.20181 98.40732 97.61660 96.82975 96.04686 95.26804 94.49339
[9] 93.72300 92.95698 92.19544 91.43850 90.68627 89.93887 89.19641 88.45903
[17] 87.72685 87.00000 86.27862 85.56284 84.85281 84.14868 83.45058 82.75869
[25] 82.07314 81.39410 80.72174 80.05623 79.39773 78.74643 78.10250 77.46612
[33] 76.83749 76.21680 75.60423 75.00000 74.40430 73.81734 73.23933 72.67049
[41] 72.11103 71.56116 71.02112 70.49113 69.97142 69.46222 68.96376 68.47627
[49] 68.00000 67.53518 67.08204 66.64083 66.21178 65.79514 65.39113 65.00000
[57] 64.62198 64.25730 63.90618 63.56886 63.24555 62.93648 62.64184 62.36185
[65] 62.09670 61.84658 61.61169 61.39218 61.18823 61.00000 60.82763 60.67125
[73] 60.53098 60.40695 60.29925 60.20797 60.13319 60.07495 60.03332 60.00833
[81] 60.00000

 さて、数字の並びを見てもつまらないから、これをグラフにしてみたい。グラフを描くのも、Rでは簡単だ。

> # プロット
> plot(Bt(100, 80, 80:0, 1.0), 80:0, "l", xlim=c(100, 60))

 Btsに値が格納されているなら、

> plot(Bts, 80:0, "l", xlim=c(100, 60))

でよい。そうすると、画像のようなグラフがたちどころに表示される。

 これは、80人対100人で戦って、劣軍(80人)側が全滅したときに優軍(100人)側が何人残るか、というグラフである。「自乗」がよくきき、最初互角に戦っているように見えて、ある時点から急速に80人側が損耗し、80人側が全滅したとき、100人側には60人もの残存兵力があることがわかる。

 そうすると、劣軍のほうは、「量より質」で勝負、ということになるから、先に出た「E」を、互角の損耗になるように求めればよい。Rでは次の如しである。

> # 函数E
> E<-function(B0, Bt, R0, Rt){
+ E<-(B0^2 - Bt^2)/(R0^2 - Rt^2)
+ E
+ }
> E(100, 0, 80, 0)
[1] 1.5625

 最後に出ている、「1.5625」、約1.6というのが、劣軍が持たなければならない「質」である。なんでもよい、命中率が1.6倍でも、飛行機のスピードが1.6倍でもよい。しかし、「モノの性能や人の能力が1.6倍」ということがどんなに難しいことか、論じるまでもない。オリンピックのスキー・ジャンプの選手が、相手が100メートル飛ぶところを160メートル飛ぶなどと、そんな途方もない実力差など到底保ち得ないことからも、それはイメージできる。

 ここで、ちょっと、英雄・東郷平八郎元帥を揶揄してみよう。

 日本海海戦にみごとな勝利をおさめた元帥が、戦後聯合艦隊を解散するに当たり、部下幕僚の秋山真之をして起案せしめた名文に、「聯合艦隊解散之辞」がある。その中の一節は不朽の名文として後世に残る。

(前略)
而して武力なるものは艦船兵器等のみにあらずして、之を活用する無形の実力にあり。百発百中の一砲()く百発一中の敵砲百門に対抗し得るを(さと)らば、我等軍人は主として武力を形而上に求めざるべからず。
(後略)

 さて、では、100対1の勝負、そして100門側の命中率は100発中1発命中、すなわち0.01、かたやは100発中100発命中、というからにはすなわちこれは1.0であり、その性能比は100になんなんとする。

 では、これを、Rを使って確かめてみよう。100対1だとグラフにしにくいから、1000対10にする。

> Bts<-Bt(1000, 10, 10:0, 100.0)
> Bts
[1] 1000.0000 999.0495 998.1984 997.4467 996.7949 996.2429 995.7911 995.4396
[9] 995.1884 995.0377 994.9874

…あっれ~…。どうも、ヘンだぞ、この数字は(笑)。グラフにしてみよう。

> plot(Bts, 10:0, "l", xlim=c(1000, 994))

 ……ダメじゃん。全然。東郷さん、相手を5門もやっつけないうちに、10門、全滅してんじゃん。秒殺じゃん。っていうか、これ、瞬殺のレベルでしょ。

 秋山真之~ッ!!ウソ書くな~ッ(笑)。

 じゃあ、なんで、日本海海戦に、弱い日本が勝てたの?どうしてどうして!?

 ……これは皆さん、実は日本海軍は当時劣勢海軍などではなかったのだ。ユダヤ商人からなりふりかまわず借金しまくり、戦闘艦艇を買いあさり、乾坤一擲の大勢力を作り上げていたのだ。これらはあげて一丸となってバルチック艦隊に襲いかかっている。

 数において劣り、かつアフリカ回り、インド洋、南洋回り航路を遠路はるばるやってきて、疲弊しきっているバルチック艦隊を容赦なく待ち伏せ、さながら弱い者イジメのように袋叩きにしたという歴史的事実は知る人ぞ知るところである。そして、日本がそのためにした借金を返し終わるのに、実に82年後の昭和61年(1986)までかかっているのも、よく知られている。

 「『数において劣る』だって!?いや、たしか、艦艇の数は互角だったんじゃなかったっけ?」

……と、詳しい向きは言うかもしれない。だが、双方の主要な火力であった15サンチ砲の門数だけを見ると、聯合艦隊204門に対してバルチック艦隊152門で、聯合艦隊が(まさ)るのだ。これをRに入れてみると、

> Bts<-Bt(204, 152, 152:0, 1.0)
> Bts
[1] 204.0000 203.2560 202.5142 201.7746 201.0373 200.3023 199.5695 198.8391
~中略~
[153] 136.0588
> plot(Bts, 152:0, "l", xlim=c(200, 133))

 バルチック艦隊全滅時点で、聯合艦隊はまだ半分以上、136門の火力が残存しているのである。聯合艦隊の全艦艇は91隻、平均すると一隻につき2門の15サンチ砲を積んでいたことになるから、その片砲を失っていても、まだ船自体は沈まない。だから東郷平八郎が、「数に劣る日本軍は、腕前と作戦で勝った」と言っているのは、ウソなのである。数で押しまくり、バルチック艦隊を袋叩きにしただけだ。

 さておき、この「東郷平八郎・ランチェスター検証ネタ」は、私・佐藤のオリジナル着目ではない。オペレーションズ・リサーチの専門家の間ではよくネタとして取り上げられるものであることを断っておく。また、恐ろしい戦争で、恐怖に耐えて一生懸命に戦った下士官兵たちを、「よくやった!お前たちの精神力がまさっていたから、勝った!!だが油断するなよ!」と、提督として元気付けている類の話を、数字の計算だけを論拠にウソだなどと言い立てることは、必ずしも正しいことではないと、漏れなく付言しておきたい。

 さて、ここまでならExcelなどでも簡単にできることだ。ひとつ、Excelではちょっと難しい量の数字を、この面白そうな「R」言語に、叩き込んでみようではないか。

お題:「13億4千万の中国人と、1億3千万の日本人が全員で殺し合いをする」

…いや、これ、計算する前から結果は見えてるんですけど(笑)、そうじゃなくて、まあ、デケぇ数字でもRは扱えまっせ、というところを試したいのである。 このお題、エクセルで兵力の推移などを表で見ようとすると、人口が多すぎて、行数が足りなくなったりするからだ。

> Bts<-Bt(1340000000, 130000000, 130000000:0, 1.0)
エラー: サイズ 991.8 Mb のベクトルを割り当てることができません

…ありゃ(笑)。さすがに13億とか1億3千万とか配列に入れると、チトムリだったみたいだ。一桁減らそう。

> Bts<-Bt(134000000, 13000000, 13000000:0, 1.0)

 サクッと配列に表が格納される。プロットしてみよう。

> plot(Bts, 13000000:0, "l", xlim=c(134000000, 133300000))

 中国側が13億4千万から、13億3千万にまで減らない間に、日本はゼロ人。1億3千万人が全滅である。

 では、ハイテク兵器などで武装して、量より質でがんばりましょう、としたとき、日本はどれほどの命中率、どれほどのスピード、どれほどの爆発力、どれほどの優れた人材を備えて、はじめて互角になるでしょうか、という数字が…

> E(1340000000, 0, 130000000, 0)
[1] 106.2485

…となる。106倍。

 そんな、アンタね(笑)。中国の兵隊の知能指数が日本の100分の1であるとか、日本の飛行機が中国の飛行機の100倍のスピードで飛ぶとか、そんなのムリに決まってる。中国軍の100倍の厳しい訓練を自衛隊がしたって、100倍の能力にはならないのだ。

 さて、これが今日の昼下がりの、「R」を使った、ちょっとした暗いお遊びでございました。どっとはらい。