トップ 追記

日々の破片

Subscribe with livedoor Reader
著作一覧

2016-09-30

_ コマンドラインプログラムのライブラリ化

何か問題があると、すぐさまexit(n)とかで抜けてしまうプログラムをライブラリにしなければならず、いろいろ弱ったが、考えてみればそのための大域脱出だった。

たとえば元のプログラムが

#inculde <stdio.h>
// ...
int fatal(char* tmpl, ...)
{
  va_list argp;
  ...
  vprintf(tmpl, argp);
  exit(4);
}
void do_extract(char* src, char* dst)
{
   ...
}
int main(int argc, char* argv[])
{
    if (!strcmp(argv[1], "extract")) do_extract(argv[2], argv[3]);
    else if (...
}

だった場合、

#include <setjmp.h>
static jmp_buf env;
int fatal(char* impl, ...)
{
  va_list argp;
  ...
  vprintf(tmpl, argp);
  longjmp(env, 4);
}
int do_extract(char* src, char* dst)
{
   int exitcode = setjmp(env);
   if (exitcode) return exitcode;
   // 元の処理
   return 0;
}

で、問題はもしこのライブラリを呼び出すプログラムが延々と動作する場合で、かつライブラリの中でmallocやfopenをしまくると、巻き戻しがされないことだ。

その場合は、jmp_bufをスタックにすれば良いのかな?

static int ijmp = 0;
static jmp_buf env[32];
int fatal(char* impl, ...)
{
  va_list argp;
  ...
  vprintf(tmpl, argp);
  longjmp(env[--ijmp], 4);
}
void memallocfn()
{
    char* mem = NULL;
    int exitcode = setjmp(env[ijmp++]);
    if (exitcode) 
    {
        free(mem);
        longjmp(env[--ijmp], exitcode);
    }
    mem = malloc(BUFF_SIZE);
    if (!mem) fatal("can't allocate memblock (%d) %d", BUFF_SIZE, errno);
    ...
    free(mem);
}

2016-09-25

_ たのしいムーミン一家

かれこれ10年以上前に子供からおもしろいから読めと言われて渡されたまま放置していた『たのしいムーミン一家』を読んだ。あっという間だった。TwitterのTL見ると12:17頃に読み始めて14:16には読了しているから2時間くらいか(途中昼飯食っているはずだから映画1本90分という感じかな)。

冒頭でいきなりスナフキンがムーミントロールと一緒に冬眠に入るところで驚いた。ムムリク族はもう少し人間なのかと思っていた(人間世界も旅しているから公園のエピソードとかあるわけだろうからもっと人間に近いと思い込んでいたのだ、海のトリトンが卵に驚くところみたいだな)。

で春が来て目が覚めて読み始めたが、噂には聞いていた通りに非常にシニカルなところがあり、妙なニヒリズムありで、実に楽しい。お互いに毒づきながら楽しく愉快に暮らしているところが、心地よいのだな。

最後の大団円の頓智や、その前のどれだけ恐ろしいことが起きるのかと思うと、とっても紳士な態度をとるところとかも良い感じだ。そのあたりでうまさにしびれたのは、ジャコウネズミの願いを真に叶えてしまうところだ。というか、スノークのお嬢さんが驚くほど俗っぽいところと、ムーミンママが世界をルールしているところとか、ヘムリンさんが子供と同じ立ち位置にいるところとか、読まなきゃ知らないまま終わっていただろうところがいちいちおもしろい。全世界の切手を集め終わると、収集家ではなくコレクションの持ち主に進化してしまって少しもおもしろくないというのは良い感覚だなと思った(部屋の中で1番賢くなるなってやつに1脈通じるものがある)。

堪能しまくりの約2時間だった。

たのしいムーミン一家 (新装版) (講談社青い鳥文庫)(トーベ・ヤンソン/山室 静)

(読んだのは元の版のほう。気ちがいみたいにという形容が出て来てちょっとどきどきした(くらいにPCに訓致されている)が、新装版では修正されているのじゃないかな)

解説にフィンランドの主となる民族はアジア系(トーベヤンソンはそれに対してスェーデン系ということはアーリア民族ってことだろうが)だとあるけど本当なのかな?


2016-09-19

_ Visual StudioでclangでC11を試す(が)

C11のAppendix Kを試してみたくて、bash on Windowsのclangで次のコードをコンパイルした。

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
int main()
{
    char tmp[80];
    int n = scanf_s("%s", tmp); // => コンパイルエラーとなる
    if (n > 0) {
        puts(tmp);
    }
}

するとscanf_sは未定義だと警告され、結局はリンクエラーとなる。

test.c:(.text+0x1e): `scanf_s' に対する定義されていない参照です

/usr/include/studio.hを見たら、確かに定義が存在しない。

まあAppendix Kはオプションだからそんなものかも知れない。

でも待て、Visual Studio 2015 - Clang with Microsoft CodeGenなら行けるのではないか? と考えた。

というのは、clang with MS CodeGenでclang用に追加されるincludeディレクトリはC:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\ClangC2\includeで、ここにはstdio.hは存在しないからだ。

つまり、stdio.hはVC++のヘッダを共通で利用することになる。

で、コンパイルすると、無事コンパイルが成功する。

……いや、コンパイルが成功するのは期待する動作ではない。

期待する動作は、VC++がそうするようにコンパイルエラーとなることだ。

VC++は上記のソースをコンパイルすると次のエラーを吐く。

test.c
test.c(8): warning C4473: 'scanf_s': 書式文字列として渡された引数が不足しています
test.c(8): note: プレースホルダーとそのパラメーターには 2 の可変個引数が必要ですが、1 が指定されています。
test.c(8): note: 不足している可変個引数 2 が書式文字列 '%s' に必要です
test.c(8): note: この引数はバッファー サイズとして使用されます

で、予想されるように、clangでコンパイルしたプログラムは実行できて、かつ動作は予想できない。バッファサイズを与えていないから何文字入力できるか不明だし、とりあえず山ほど入力すれば0xC0000005で死ぬ。

これはちょっとひどいのではないか? まだ、scanf_sは未定義といって怒るほうが1000億倍ましだ。

もちろん以下のように書き直すと、期待通りに動作する。

#define __STDC_WANT_LIB_EXT1__ 1  // <= これ結局本当におまじない以上の意味が無いということだな
#include <stdio.h>
int main()
{
    char tmp[80];
    int n = scanf_s("%s", tmp, (unsigned)sizeof(tmp)); // x64でも通るようにするには(unsigned)キャストが必要(size_tではない)
    if (n > 0) {
        puts(tmp);
    }
}


2016-09-18

_ バトル用ポケモンの組み方

現在のジム状況はCP2000越えのカイリューやカビゴンが主流となっている。

ここで問題となるのは、相手チームのジムに対する攻撃ではなく、自チームのジムに対する道場破りだ。(相手チームはとにかく全滅させれば良いので、こちらも高CPのカイリューを用意してひたすらタコ殴りすれば良い)

例として、レベル3で既に3頭が置かれている自チームのジムに自ポケモンを配備する場合を考える。

素の状態のレベル1のジムの名声は1000、レベル2のジムは2000、レベル3のジムは4000なので、これを8000に持ち上げればレベル4となり、自ポケモンが置ける。

今、ジムにはCP500のカメール(多分、置いてみたかったのだろう)、1900のギャラドス、2000のシャワーズがいるとする。

ここで、CP2800のカイリューで殴り込みをかけてタコ殴りで突破したとする。

この場合、得られる名声はたかだか350とかそんなものだ。というのは、どうも倒した場合の名声(これは得られるXPの10倍に相当する)は、最後に倒した相手ポケモンのCPを自ポケモンのCPで割った数に500を乗じたものだからだ(と断言してよいかは知らないけど、FBで読んだ河合さん(面識ないから良くわからないけど、友達の友達なので読めているのだと思う)の投稿から。確かにそういう結果になる)

ということは、2000/2800*500≒357

なので、XPは35、名声は+357で、さっきまで4000だったものが4357になる。あと何回タコ殴りすれば良いのだろうか?

ここで、手元にCP1500のサンダーズがいるとする。

カメールもギャラドスも水ポケモンなので、頑張れば2人抜きはできる可能性がある。最後のシャワーズは出てきた瞬間に降参するのがミソ(ただし、元気のかけらといい傷クスリのペアが、すごい傷クスリよりも多ければ、降参せずに倒されたほうがむしろ良いとか、持ち物のストックによって多少戦略が変わる。基本はスピード重視なのでさっさと降参するほうが良い)

この場合、

1900/1500*500≒633

となり、XPは63、名声は+633でさっきタコ殴りで4357になった名声が一気に4990になった。あと5回サンダーズが頑張れば名声が8155になる(得られるXPは315)。

CP2000が主流である以上、CP1300~1500で相性が良く連打が効くか強力な一発技を持つ中堅層を保持しておくと実によいことになる。

というわけで、以下が対自チームジム戦の現在の主力だ。

・2000CPのギャラドス(ラッキーなことに龍の息吹と龍の波動持ち)→3000CPカイリュー(いきなりこいつが留守番しているジムもそこそこある。が、多いのは2000CPカイリューなので得られるXPも名声もそれほどではないことが多い)を結構倒せる(ただし破壊光線や龍の波動を回避できれば)

・1500CPのかみなりサンダーズ(かっては対相手チームバトルの主役だったが、全体のCPが上がった結果、ベンチを温めることが多かったが、ここに来て復活)→CP2000前後のギャラドス、シャワーズ用(ハイドロポンプを回避できれば勝てる)

・1500CPの地震サイドン(よりも技1が格闘なのがでかい)→CP2000前後のカビゴン(破壊光線を回避できれば勝てる)

・1500CPのソーラービームウツボット→CP2000前後のギャラドス、シャワーズ用

・1300CPの暴風ピジョット→2000CP以下のナッシー(ソーラービームは比較的回避できるが、タネ爆弾持ちにはたいていやられてしまうのが難)

・1500CPのハイドロシャワーズ→2000越えのブースターやウィンディ(大文字1回受けても余裕で勝てる。が、シャワーズが大技を「避けた」するときはくるっと実に優雅にバク転するので、これが見たくて回避動作をさせることも多い)

というわけで、技は比較的重要だが、それ以上に種族相性がもっと重要だということでした。

まとめると対相手チームジムバトルではなく、対自チームジムバトルにおいては、低CP高バトル能力+技相性戦略が重要というのが結論。


で、これを応用して仲間でやるのであれば、あえてCP高いが無能(個体値ではなく、技1と2がしょぼいやつ)なやつにジム番させて、交互に倒してXP稼ぎながらジムレベルを上げまくって、全員の高CPポケモンを投入すれば(空きができ次第投入すれば良いわけだが、最初に配備させたへなちょこよりも低CPだと意味がない)、難攻不落のバベルの塔ができるのだが、そういうそびえたつジムは今のところ見たことがない。

とにかくCPが2/3~1/2程度のポケモンが余裕で倒せるへなちょこ(あるいは低HP)は、飴にするよりもそのほうが有効だと思う(カイロスとかアズマオウとかがお勧め(追記:と書いたが(後のほうで書いているドリルライナーのアニメがおもしろいと書きたかったためにちょっと現実を捻じ曲げてしまった)、こいつら2000にするのはもったいないが、素で1000くらいだとCP500の中途半端なやつでバトルすることになって、それはそれで今度は勝つのが難しい。竜巻ギャラドスあたりが狙い目かな)。ちなみにアズマオウのドリルライナーは回避が簡単なわりには見た目が面白いので一度は配備してバトルするとおもしろいと思う)。


2016-09-12

_ C++によるプログラミングの原則と実践(続)

なんか精読し始めたら止まらなくなってしまった(ぱらぱら読むのではだめだなぁ)。

この本は抜群に優れているではないか。さすがだぜストラウストラップ。

というわけで、続き

第3章の練習問題4は間違っている。

誤)「整数値を1つ入力させるプログラムを記述する」

正)「整数値を2つ入力させるプログラムを記述する」

第4章の「コンピュテーション」はおそらく白眉だ。ストラウストラップ自身が最後のところで、ここで語り尽したみたいなことを書いている(まあ、意味は、プログラムの意味ということについてだけだが)。

しかし惜しいかな、いきなり重要なところを誤訳している。

P.83 4.2.

多分誤)「正しく効率のよいプログラムは複雑であり」

こうでなければおかしい)「正しく効率のよいプログラムであっても複雑過ぎれば」

重要な主張はプログラマーの仕事を、「計算を次のように表現することだ」と順位付けしている点にある。

・正しく(プライオリティーNo.1)

・単純に(プライオリティーNo.2)

・効率よく(プライオリティーNo.3)

したがって、複雑さよりも単純さを尊ぶ。よくわかる。

そしてP.84がすばらしい。引用する。

正確さ、単純さ、効率のよさに関心を抱くのは、コードを他人のために記述し、それをうまく行うことに責任を負った瞬間だ。つまり、プロになることを決意したら、その責任を負うのは当然のことだ。

いや、本当に、この言葉をすべてのくそコードの山をひり出した連中にのしをつけて送りつけてやりたい。

これこそが肝要ではないか。

ここからP.85まで、つまり、4.2.「目的とツール」は毎日お題目として唱えさせたいくらいだ。

P.105の4.5.1.関数を使用する理由は、正しいが、今となっては弱弱しい。

この理屈(計算の論理的な分割、名前によりコードが明確化、プログラムを複数の場所から利用可能、テストが容易)の3番目を軽く凌駕する、「最近のエディターを使えば、コピー&ペーストというものが使えるのですよ? いつの時代の紙テーププログラマーorパンチカードプログラマーですか?」というごみな見解を覆すことは難しいだろう(そういう了見の連中は、論理的な分割は能力的にできないし、名前を持たないし、テストをしないからな)。

だから、関数化(モジュール化と言い換えても良い)には、もっと積極的な理由が必要なのだと考えるが、このあたりが良識的で優秀な著者の限界というものだろう。

P.117。バグ。言及していないbegin()およびend()についての問題と用語への掲載がある。おそらく元はイテレータを利用していたのを、「:」を利用したイテレーションに書き換えたことに追随していないのではないかと推測する。

C++によるプログラミングの原則と実践(Bjarne Stroustrup/江添 亮/株式会社クイープ/遠藤美代子)

clangで本書の例やサンプルをコンパイルするには

clang++ -std=c++11 ファイル名

とする。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|

ジェズイットを見習え