[Home]-[以前のひとこと]-[2006年1月前半]

以前の「ひとこと」 : 2006年1月前半



1月1日(日) 百人一首(その1)

 あけましておめでとうございます。本年も「あそびをせんとや」をよろしくお願い致します。



 今年のお正月は、家族で何度か百人一首をやりました。家族4人で25枚ずつ自分のほうを向けてならべてやったのですが、誰がだれの札を取っても、特に札のやりとりはせずに、単純に最後まで取った枚数で競うというやり方にしました。私が読み手になって、上の句を読み終わるまでは顔を上げないで、下の句を読み始めたところから探し始めるということで、取る側にも参加してやりました。子供たちはまだまだぜんぜん覚えていないのですが、それでも下の句を1回読み終わるまでには取れるようになってくれて、やっていて楽しいです。

 百人一首の朗詠のしかたというのはきっとどこでも似たようなものなのだろうと思うのですが、私が子供の頃、うちではこんな詠み方をしていました。(音声合成ソフトに歌わせようかと思ったのですが、ファイルサイズが大きくなるのでピアノの音色のMIDIにしてみました。)

 基本的には5・7・5を4拍子のリズムに当てはめて歌います。下の例のようにシンコペーションになる場合もあります。

 これとはちょっと違う詠み方もありました。明日の更新の分でもう一方をご紹介します。確か、どちらかが私の父の詠み方で、もう一方が私の母の詠み方だった記憶があるのですが、どちらがどちらだったのか忘れてしまいました。

(つづく)

<おまけのひとこと>
 今年は元旦の朝は曇っていました。






1月2日(月) 百人一首(その2)

 百人一首の朗詠の仕方のご紹介の2回目です。 こんなパターンの詠み方もあります。

 もう1つ、最後がちょっと違う詠み方もしていました。

 たとえば子供の頃、友達の家に行って「○○○ちゃん、あ・そ・ぼ!」とか、誰かが教室で何かを壊してしまったときに「いーけなぃんだーいけなぃんだー、せーんせーに言ってやろー」とか、ふしを付けてうたったものですが、そんなのと同じく、きっとどこでも百人一首はこんなふうに歌っているんだろうな、と思っているのですが、改めて誰かに尋ねてみたことはないのでわかりません。

<おまけのひとこと>
 最近は本を読む時間がなかなかとれなかったので、このお休みは、家族がテレビなどを見ている時間にひたすら本を読んでいます。






1月3日(火) C言語:呼び出し元関数内の自動変数値を書き換える(その1)

 この年末年始休みには、「宿題」を持ち帰っているのですが、その仕事を進めながら、ちょっと書きたくなった話を書いておきます。コンピュータ言語のC言語の話です。興味のない方は申しわけありません。

 昨年の11月11日のひとことで、阿原先生のコンピュータ演習の問題で遊んでみたという話を書きましたが、そのときに、正統派の方法と、ルール違反の方法についてちょっとコメントさせていただきました。今日は、この「ルール違反」の方法について紹介します。

 阿原先生の問題は、アルゴリズムの演習ということで、予め用意された10名のコンピュータプレーヤーに対して、自分で考えたアルゴリズムを対戦させて、各対戦の合計点の最大を競うゲームでした。自分のアルゴリズムを含め、それぞれのプレーヤーはC言語の1つの関数で表されています。対戦を制御するプログラムがそれぞれの関数を呼び出してその結果を記録し、最後に結果を印字して終わるというもので、対戦相手の関数も対戦制御の関数もすべてプログラムのソースコードは公開されています。 さてこの条件下で、対戦制御関数の中身にアクセスすることは可能でしょうか。

 C言語には、auto変数(自動変数)と呼ばれる変数があります。これは関数やブロックの先頭で宣言された変数で、そのメモリ領域は関数が呼び出されたときに自動的に確保されて、関数から抜けると捨てられてしまう(その変数は有効でなくなる)というもので、再びその関数が呼び出されたときには、auto変数の中身は何が入っているかは保障されない、というものです。そして、関数の外からはその変数にはアクセスできないというものです。

 阿原先生の問題では、C言語のこの仕様を利用して、合計点(totalpoint)という変数に得点を積算していって、最後に平均値を印字させたりしています。

main()
{
	int i,j;
	int a0,a1;
	int maxnumber = 10;
	int point0,point1;
	long totalpoint=0;

	・
	・
	・

ske106.cppより

 この totalpoint という auto変数を、main()関数から呼び出されるユーザ関数 player0() の中から書き換えることはできるでしょうか? もちろん、player0() 関数以外のソースコードは1文字たりとも書き換えずに、です。

 昔々、コンピュータやネットワークの黎明期には、メモリや演算能力やネットワークの伝送量は非常に限られていたので、悪意や不正を前提とした処理を行う余裕はありませんでしたし、そんな必要もありませんでした。 現在はコンピュータの能力も非常に上がり、ネットワークの帯域も非常に広がり、そしてコンピュータの世界は「悪意」だらけです。

(つづく)

<おまけのひとこと>
 年が明けて、穏やかで、極端には寒くない日が続いています。






1月4日(水) C言語:呼び出し元関数内の自動変数値を書き換える(その2)

 さて、昨日の「呼び出し先の関数の中から、呼び出し元の関数の変数にアクセスする」ということができるのか、ちょっと実験してみましょう。下の「ソース1」と書かれたプログラムをご覧下さい。


foo()
{
	int x,y;

	printf("&x=0x%lx, &y=0x%lx\n",(int)&x,(int)&y);
}


main()
{
	int a,b,c;

	a = foo();
	printf("&a=0x%lx,&b=0x%lx,&c=0x%lx\n",(int)&a,(int)&b,(int)&c);
}





&x=0x12ff68, &y=0x12ff64








&a=0x12ff7c,&b=0x12ff78,&c=0x12ff74

ソース1 出力1

 main()関数から、最初に foo() という関数を呼んで、その関数のローカル変数 x,y のアドレスを印字させます。 foo() から戻ってきたところで、今度は main() 関数のローカル変数 a,b,c のアドレスを印字させます。その結果が出力1です。

 0x12ff68 なんていうなんだかよくわからない文字が表示されていますが、これは16進数で表した変数のアドレスです。もちろん、これはこのプログラムをコンパイルしたコンパイラや、このプログラムを実行するOSや環境によって違った値になることのほうが多いものです。

 さて、この出力をみると、呼び出し元のmain()関数のローカル変数と、呼び出し先のfoo()関数のローカル変数のアドレスは、実はかなり近いということがわかります。(出力の数値がよく似ています。)xとyのアドレス、a,b,cそれぞれのアドレスの数値は4ずつ異なっていますが、これはこのソースコードをコンパイルしたコンパイラの環境では、int 型(整数型)の変数のメモリ上のサイズが4バイト(=32bit)であるためです。

 そこで、次にこんな実験をしてみましょう。さきほどとは foo() の変数x,y と main()の変数a,b,cのアドレスを印字しただけでしたが、今度は、xやyのアドレスの先のメモリの中身を整数型だと思って無理やり読ませて、それを表示してみましょう。

foo(int n)
{
	int x,y;

	x=100;
	y=200;
	printf("&x = 0x%lx\n",(int)&x);
	printf("&y = 0x%lx\n",(int)&y);
	printf("&n = 0x%lx\n",(int)&n);

	printf("\n");
	printf("x = %ld\n",x);
	printf("y = %ld\n",y);
	printf("\n");

	printf("((int *)(&y))[ 0] = %ld\n",((int *)(&y))[0]);
	printf("((int *)(&y))[ 1] = %ld\n",((int *)(&y))[1]);
	printf("((int *)(&y))[ 2] = %ld\n",((int *)(&y))[2]);
	printf("((int *)(&y))[ 3] = %ld\n",((int *)(&y))[3]);
	printf("((int *)(&y))[ 4] = %ld\n",((int *)(&y))[4]);
	printf("((int *)(&y))[ 5] = %ld\n",((int *)(&y))[5]);
	printf("((int *)(&y))[ 6] = %ld\n",((int *)(&y))[6]);
	printf("((int *)(&y))[ 7] = %ld\n",((int *)(&y))[7]);
	printf("((int *)(&y))[ 8] = %ld\n",((int *)(&y))[8]);
	printf("((int *)(&y))[ 9] = %ld\n",((int *)(&y))[9]);
	printf("((int *)(&y))[10] = %ld\n",((int *)(&y))[10]);

}

main()
{
	int a,b,c;

	a=1000;
	b=2000;
	c=3000;

	printf("\n");
	printf("a = %ld\n",a);
	printf("b = %ld\n",b);
	printf("c = %ld\n",c);
	printf("\n");

	foo(1);
	printf("\n");
	printf("&a = 0x%lx\n",(int)&a);
	printf("&b = 0x%lx\n",(int)&b);
	printf("&c = 0x%lx\n",(int)&c);
}






&x = 0x12ff64
&y = 0x12ff60
&n = 0x12ff70


x = 100
y = 200


((int *)(&y))[ 0] = 200
((int *)(&y))[ 1] = 100
((int *)(&y))[ 2] = 1245056
((int *)(&y))[ 3] = 4198833
((int *)(&y))[ 4] = 1
((int *)(&y))[ 5] = 3000
((int *)(&y))[ 6] = 2000
((int *)(&y))[ 7] = 1000
((int *)(&y))[ 8] = 1245120
((int *)(&y))[ 9] = 4199133
((int *)(&y))[10] = 1












a = 1000
b = 2000
c = 3000




&a = 0x12ff7c
&b = 0x12ff78
&c = 0x12ff74

a = 1000
b = 2000
c = 3000

&x = 0x12ff64
&y = 0x12ff60
&n = 0x12ff70

x = 100
y = 200

((int *)(&y))[ 0] = 200
((int *)(&y))[ 1] = 100
((int *)(&y))[ 2] = 1245056
((int *)(&y))[ 3] = 4198833
((int *)(&y))[ 4] = 1
((int *)(&y))[ 5] = 3000
((int *)(&y))[ 6] = 2000
((int *)(&y))[ 7] = 1000
((int *)(&y))[ 8] = 1245120
((int *)(&y))[ 9] = 4199133
((int *)(&y))[10] = 1

&a = 0x12ff7c
&b = 0x12ff78
&c = 0x12ff74
ソース2 ソース対応出力 実際の出力

 main()関数の最初で、まず a,b,c に1000,2000,3000という数値を入れて、その直後にprintf()で印字しておきます。それから foo() 関数を呼び出して、ローカル変数 x,y を 100,200 で初期化しておいて、それもただちに印字してから、今度は変数y のアドレスから、整数型11個分の値を1つずつ読ませて表示させてみています。するととてもおもしろいことに、「200,100」という数字の並びと、「3000,2000,1000」という数字の並びがあることに気がつきます。

 この数字が偶然ではない証拠に、a,b,cの初期化の数値を変えても、やっぱり同じところに初期化した数値が現れます。ただしコンパイラやコンパイルオプション、実行環境などが異なると、「3000,2000,1000」という数字の並びが出てくる場所が変わることもありますし(yのアドレスから10個くらい印字しただけでは出てこない場合もある)、場合によっては順番が変わることもあるかもしれません。

(つづく)

<おまけのひとこと>
 すみません、更新に時間がかかるわりには、こんなことを書いても面白いと思っていただける方は少ないかなと思うのですが、もう1〜2回、こんな話題を書かせてもらいます。






1月5日(木) C言語:呼び出し元関数内の自動変数値を書き換える(その3)

 昨日の続きで、呼び出された関数の中から、呼び出し元の関数の変数をこっそり書き換えてしまうには、という話です。

 昨日の実験から、「特定のコンパイラの特定のコンパイルオプションでは」、呼び出し元の関数の自動変数と呼び出し先の関数の自動変数の間には、メモリの上での一定の関係があるらしいということがわかりました。それに基づいて作ってみたのが、本日の「ソース3」です。

foo()
{
	int auto1;
	int *p;

	p=&auto1;
	p[10] = 400;
	p[9] = 600;
}


main()
{
	int i,j;
	int a0,a1;
	int maxnumber = 10;
	int point0,point1;
	long totalpoint=0;

	point0=100; point1=200;
	printf("before : point0 = %ld, point1=%ld\n",point0, point1);

	foo();

	printf("after  : point0 = %ld, point1=%ld\n",point0, point1);

}




















before : point0 = 100, point1=200



after  : point0 = 400, point1=600


ソース3 出力3

 main()関数の自動変数は、今回の実験のそもそもの発端となった阿原先生の演習のプログラムのmain()関数のものをそのまま踏襲しています。ここでは、その中の point0, point1 という2つの変数に注目して、最初にmain()関数の中でこの2つの値を 100と200 にしておいて、foo() という関数を引数なしで呼び出したら、それだけで point0, point1 の値が書き換わってしまうというものです。

 foo() 関数の中身を見てみると、p というポインタ変数に、foo() 自身の自動変数のアドレスを代入して、そこからint型にして9番目と10番目のアドレス位置に400と600という値を書き込んでいるのがわかります。もちろんこれは通常のC言語としては全くナンセンスなコードで、こんなアドレスに無理やり値を書き込むと、動作の保障はありません。

 上のコードは Visual C++ の 6.0 というバージョンのコンパイラで、特に最適化オプション等何もつけずにコマンドラインから cl.exe でコンパイルすると出力3の結果が得られましたが、たとえば同じOSの上でも、cygwin の gcc でコンパイルすると、point0,point1 の値は変わりませんでした。

 通常のC言語の実装では、こういった自動変数というのは「スタック」と呼ばれるメモリ領域に確保されます。関数を呼び出すときには、この「スタック」の上にさまざまな情報が保存されて、呼び出し先の関数から帰ってきたときにちゃんと動作を継続できるようにしているのです。また、呼び出し先の関数の実行が終了したら、そもそもどこに戻るべきかという情報もここに記録されます。

 上の「ソース3」のfoo() 関数では、スタック上にとられた自分の自動変数のアドレスから特定の相対位置の中身を無邪気に書き直しています。この例ではたまたま戻るべきmain()関数の自動変数を書き換えただけですみましたが、もしも戻るべき実行位置を書き換えてしまったら、プログラムはそこから動作を継続しようとするはずです。



 プログラムの脆弱性を利用して悪意あるコードを実行させるという、コンピュータに対する攻撃方法があります。そのなかでも有名なテクニックが「バッファ=オーバーラン」という方法です。プログラムがスタックの上に用意した、ユーザからのデータを読み込んで一時的に蓄えておく場所に、用意された容量以上のデータを読み込ませることで、関数から戻るアドレスを上書きしてしまうというやり口です。

 C言語というのはFORTRANのように数式処理をする手続型言語として学ばれることが多いかもしれませんが、実態は「ちょっと高級なアセンブラ」で、上記のようなことが簡単にできてしまう言語です。

 「毒を食らわば・・・」ということで、実は阿原先生の課題で、コンパイル環境に依存しない、呼び出し元のmain()関数の特定の変数のアドレスを特定してそれを書き換えるというコードもちょっと考えてみたのですが、なかなか難しいです。特に、最適化オプションによっては、自動変数がレジスタ変数になる場合があったり、メモリ上の変数の順序が宣言の順序と入れ替わったりということが起こるのです。とりあえず最適化しないならば、複数の環境で、決められた変数のアドレスを特定して書き換えるコードは作ってみましたが、まあこれはやりすぎなので公開はしません。

 ちなみに、今回ご紹介したテクニックは、自分でコンパイルやリンクすることが前提の話なので、すぐさま何か悪用できるようなものでは全くありません。「アルゴリズム演習」の解答としても、不正であることは一目でわかるので意味は成さないでしょう。(「計算機科学演習」ならば、ひょっとすると評価されるかもしれません。)高級言語の変数のスコープや寿命や名前の解決などが処理系としてどのように実装されているのかというのはとても面白いです。

<おまけのひとこと>
 すみませんおそらく多くの方には興味のない話題だったと思います。






1月6日(金) ザンベジ(SAMBESI)

 先日、ちょっとしたカードゲームを購入しました。「サンベジ」(SAMBESI)というゲームです。

図 1:パッケージ

 このゲームは、「同じもの探し」の系統のゲームです。カードは、取り札が28枚、見本の札が28枚あります。取り札はあらかじめ同心円状に全部表向きに広げておきます。見本の札は中央に伏せて山積みしておいて、1枚ずつめくって、見本の札に対応する取り札を競争で取っていきます。

図 2:プレイの様子

 札はゾウ・ライオン・ワニ・フラミンゴの4種類あって、見本の札のほうは背景が水色、取り札のほうは背景は白です。これらの動物たちが1匹ずつ「水のみ場」にやってきたという想定で、「水面に映った姿のカードを探す」というのが目的です。つまり、見本の札と全く同じものではなく、鏡像の札を探す、というところがポイントです。

 上の写真では、見本札としてゾウがいます。ゾウの鼻の向きや足元の石の位置、止まっている小鳥の位置に注意して、「鏡像の札」を探します。どれだか見つけられますか? (手前の、光が反射してしまっているカードは「フラミンゴ」ですから無関係です。)  この「同心円状に並べておく」というところと「鏡像を探す」というところが絶妙の設定だと思います。

 パッケージの説明書きによると、このゲームは人数は2〜8人、年齢は10歳以上、1回のゲームは10〜20分程度、とのことです。5人以下で遊ぶ場合は最初に6枚取った人が勝ち、6人以上で遊ぶ場合は最初に4枚取った人が勝ち、というルールでやるとよいと書かれています。

 私は記憶のゲームは苦手なのですが、こういうパターン認識系のゲームは好きなので、割と楽しめました。

<おまけのひとこと>
 昨日、寝転がって本棚の上を見ていたら、こんなものが目に入りました。



 ミニチュアワインボトルかな? と一瞬思ってしまいました。






1月7日(土) つつむ折り紙(その1):手紙包み「六角形」

 先日、図書館で布施知子さんのおりがみ つつむという本を借りてきました。

おりがみ つつむ

 おもしろい、きれいな「包み折り」がたくさん載っていて楽しいです。とても簡単なものもたくさんあります。この中から、考案者がわからない、「伝承作品」として紹介されているものをいくつか、途中経過を写真に撮ってみました。

図 1

 使う用紙ですが、正方形のものか、身の回りにたくさんあるA4とかB5とかの用紙のような、辺の比が1対ルート2の、いわゆるシルバー矩形と呼ばれる用紙が使われています。真っ白い紙だと、紙の表裏がわからないので、折り紙をシルバー矩形に切って用紙を作りました。15cm角の折り紙ならば、短辺が10.6cmになるように切ります。(不要な折線を入れないため、測って切りました。)

 図 2
 用紙を縦向きにして、谷折りで4等分します。
 図 3
 4等分した左側の折り線で畳み、左下の角を畳んだ紙の縁にあわせながら、
右側の角は4等分の線の端になるように斜めに折ります。(60度折)
 図 4
 右側からも60度折。
 これは、図3で折ってできた、90°60°30°の直角三角形の、30°の角を
90°の角に合わせるように折ります。
 図 5
 最初の4等分の縦の折り線で内側に畳む。
 図 6
 正六角形になるように、図5の上の部分を折り返す。

 !間違って60度回転させた向きで写真を撮ってしまいました!
 すみません。
 図 7
 最初の、縦の4等分の折り線を利用して、はみ出した部分を
半分に畳む。

 図 8
 左側に飛び出した部分を六角形の辺に沿って折り返す。
 図 9
 左下の正三角形の下に、はみ出した部分を差し込む。
 出来上がり。

 説明が不十分ですので、興味がある方は本を探してご覧になるとよいかと思います。

 これは「手紙包み」ですから、A4の紙などになにかメッセージを書いて、それが内側になるようにこの折り方をすれば、特に封筒などなくてもそのまま「手紙」になります。おもしろいと思います。

(つづく)

<おまけのひとこと>
 伝承作品であれば、ご紹介してもよいだろうと考えています。もちろん折り図には著作権がありますからそのまま紹介はできません。自分で写真を撮って説明文を書いたものならばよいだろうと思っています。

 冬になると折り紙をやりたくなる気がします。

 昨日、このページのアクセスカウンタが25万を越えたようです。いつもご覧いただいてありがとうございます。最近は忙しくて、アクセスカウンタの関係のイベントが実施できなくて残念に思っています。






1月8日(日) つつむ折り紙(その2):手紙包み「窓」

 昨日に続いて、布施知子さんのおりがみ つつむという本に掲載されていた伝承作品のご紹介です。 今日のものも、辺の比が1対ルート2の、「シルバー矩形」と呼ばれる比率の長方形の用紙を使います。

 図 1
 紙を横長に置いて、縦に二等分する折り線をつけ、その中央の縦の折り線に合わせて、図のように左上と右下を45°に折ります。
 図 2
 左下と右上の角を図のように45°折ります。
 図 3
 図2で折った、小さな直角二等辺三角形の上の辺に合わせて谷折りします。(上下)
 図 4
 図3で折った台形の、底角の45°を二等分するように折ります。
 図 5
 左右の直角二等辺三角形の部分を谷折りします。この直角二等辺三角形の45°の角の先端を、紙の裏面の白が見えている面に沿って差し込みます。
 図 6
 出来上がり。(この写真だけはちょっと大きいです。)

 これは、昨日の六角形のものと違ってこの中に何かを包むのによい折り方だと思います。

(つづく)

<おまけのひとこと>
 今日は朝から公民館のお掃除と、その後で小正月のどんど焼きの用意のための「のぼり建て」があります。それから公民館で新年会があります。時間がない・・・






1月9日(月) つつむ折り紙(その3):手紙包み「たけのこ」

 今日も、布施知子さんのおりがみ つつむという本に掲載されていた伝承作品のご紹介です。今日のものも1対ルート2の長方形から折り始めます。

 図 1
 紙を横長に置いて、長い辺同士をあわせて二等分の谷折りをします。
 図 2
 片側は長辺を折り線に合わせて谷折りし、反対側は2つの角を45度に折ります。
 図 3
 左上と右上を45度に折ります。
 図 4
 下の辺を、中央の横線に合わせて折ります。
 図 5
 縦線に合わせて左から折ります。
 図 6
 同じく右からも縦に折ります。
 図 7
 反対側に差し込みます。これはこれで安定した形です。
 図 8
 図7を裏返します。
 図 9
 左上を45°に折ります。
 図 10
 右上を45°に折って、差し込みます。  裏返すと・・・

図 11:完成

 冒頭にご紹介した布施知子さんの本には、もっとたくさんの「おりがみ包み」が紹介されています。お勧めです。

<おまけのひとこと>
 昨日は外仕事をして、昼から新年会でお酒を飲んで、そのあとでまた外仕事をしたらすっかり体が冷えてしまって不調です。
 小学校が明日から3学期なのですが、持ち物で揃っていないものがあるらしくて、買い物に行かないといけないようです。






1月10日(火) トランプによるバトルライン

 いつも見せていただいている濱中さんのページの1月8日の日記に、2人用のトランプゲームが紹介されていました。とても面白そうだったので、昨夜、下の子と1回やってみました。 ルールに関しては上記のページをご覧下さい。

図 1

 途中経過です。双方が14枚ずつプレイしたところです。写真だとカードがよくわからないと思うので、文字で表記してみました。1文字目がスーツ(S:スペード、H:ハート、D:ダイヤモンド、C:クラブ)を表し、2文字目が数値を表します。A:エース、2,3,4,5,6,7,8,9、T:テン(10)、J:ジャック、Q:クイーン、K:キング、です。


 -- -- -- -- -- -- -- -- --
 D7 SA S9 D6 D4 SQ -- -- --
 S7 DA CT H6 S4 CQ C3 HK --

 1 2 3 4 5 6 7 8 9

 -- CK C7 H4 D9 D3 HQ S8 --
 -- CJ C6 H3 H9 S3 -- S6 --
 -- -- -- -- -- -- -- ST --

 私は、2,3,4列でストレートフラッシュで勝とうという狙いでしたが、8列で数値の大きなフラッシュで逆転され、7列もフラッシュで負け、先に6,7,8列を取られて負けました。とても面白いゲームです。私はトランプの二人ゲームでは「クリベッジ」が一番好きなのですが、この「バトルライン」(と勝手に呼ばせていただきます)はそれに匹敵する面白いゲームですね。とても気に入りました。お勧めです。

<おまけのひとこと>
 毎日寒くて困ります。






1月11日(水) たとう折り、他

 先日、1月7日のひとことから3回ほど、「つつむ」折り紙をご紹介しました(図1)。この3つは同じ用紙から折っているのですが、大きさもかたちも厚みも、開き方・畳み方もそれぞれぜんぜん違っていて面白いです。

図 1

 これらが「伝承作品」として掲載されていた布施知子さんの本には、正方形の用紙から折る「たとう」もたくさん紹介されていました。図2の2つは、正方形から始めて、長方形や平行四辺形のようなかたちが出来る例で、おもしろいです。

図 2

 ちなみに図2は、両面折り紙という用紙を使っています。大きさは7.5cm角の正方形で、よくある普通の折り紙(15cm角)のちょうど4分の1の大きさです。



 濱中さんが、以前、「あそびをせんとや」の栞というページを作って下さっていたということを最近教えていただきました。感激です。ありがとうございます。本当は自分でこういう「索引」のようなものを作らないと不便だなと思ってはいたのですが、これがとても大変な作業になるのが目に見えていて、日々のわずかな更新のための時間ではとてもやりきれないのです。作っていただいた「栞」のページは、特に多面体工作の関係の話題に関して整理していただいているので、そういった話題に興味を持っていただける方には便利なのではと思います。ありがとうございました。

<おまけのひとこと>
 消失点よりの「藪が原の狐の話」の新作が発表になっていて嬉しいです。早速読ませていただきました。

 しごと・あそびごと・ひとりごとの、「このサイトを知っている知人には、いくら「忙しい」と訴えても信じてもらえません」に、共感というか同情しました。たいへん面白い話題を提供してくださるサイトなので、どうかご無理をなさらずに、と思っています。最近のカライドサイクルの話も面白いですね。






1月12日(木) 公平に分ける話(その1)

 完全に等分するのが難しいようなものを何人かで公平に分ける、というような問題があります。たとえば、一切れのケーキを兄弟2人で喧嘩にならないように公平に分ける、というような例から、掃除の役割分担を決めるとか、あるいは遺産を分けるとか、とにかく「みんなが納得できるように分ける」というのは、一筋縄ではいかない問題です。

 遺産分けというと、たとえば「長靴をはいた猫」というお話では、粉屋の3人息子が遺産としてそれぞれ「水車小屋」「ロバ」「猫」をもらったわけですが、これはもう「これ以上どうしようもない」分け方で、公平とは程遠いものでした。(結果的には「猫」がもっとも価値ある遺産だったわけですが)

 このようなどうしようもない場合はともかく、普通はもうちょっと公平に近づくための努力ができるはずです。遺産分けだったら、おそらく現実的には(知りませんが)金額に換算して考えることになるのではないかと思いますが、そういう大掛かりな話ではなくて、もっと身近な例、たとえば「ケーキを分ける」とか「栗ようかんを分ける」とかいうような場合を考えます。

 最初に、2人で分けることを考えます。この場合は、よく知られた「公平な分け方」というのがあって、

一人が分けて、もう一人が選ぶ

 という方法です。分け手のほうは、2つに分けたどちらを自分が取っても文句がないように、できるだけ「公平に」2つに分けます。選び手のほうは、とにかく分けてもらった2つのうち、自分が満足できるほうを選びます。こうすることで、どちらも「相手の取り分の方がいい」と思わなくて済むという方法です。 (この方法は、ロイド・アリグザンダーの「プリディン物語」の中でも出てきたのを読んだ記憶があります。)

 さて、では同じような意味で、3人で公平に分けるには、どうしたらよいでしょうか?

(つづく)

<おまけのひとこと>
 私自身は2人兄弟だったのですが、子供の頃、たとえばひとつながりの板チョコとかを公平に分けるのに苦労したものでした。

 トランプなどのカードゲームで、ディーラー(親)がカードをよくシャッフルした後で、さて実際に配る前に最後にカードを別の人にカットしてもらうという操作をしますが、これなども「一人が分けて、もう一人が選ぶ」というやり方に近い感覚があります。






1月13日(金) 公平に分ける話(その2)

 ケーキを二人で公平に分けるには、「一人が切って、もう一人が選ぶ」という方法が有効だ、ということをご紹介しました。これが3人だったらどんな方法があるでしょうか、という話をしようと思います。

 私が最初にこの問題を考えたときには、次のような手順が頭に浮かびました。

3人でケーキを公平に分ける手順の案
1. Aさんが3分の1(と思われる量)を切り取る。
2. Bさんが、残りを等分(と思われるように)分割する。
3. Cさんが、好きなものを選ぶ。
4. Bさんが、残った2つから好きなものを選ぶ。
5. Aさんが最後の残りを取る。

 一言で言うと、「さきにカットした人ほど後で選ぶ」(切先選後?)という方式です。(スタック、というデータ構造があります。たとえば箱の中に書類を積み重ねて入れてゆくとすると、取り出すときには最後に入れたものから順に取り出すことになって、最初に入れたものは最後に取り出されます。そんなイメージです。)

Aさんの戦略

 まず最初に、Aさんが全体の3分の1と思われる量を切り取ります。(これはまだAさんのものと決まったわけではありません。)もしここで3分の1よりも多く切ってしまうと、それは誰か他の人に先にとられてしまいますから不利です。逆に、3分の1よりも少なくカットしたとすると、最後にそれが自分の分として残されてしまうのでやっぱり不利です。従ってAさんの最適な戦略は、3分の1だけカットするということになります。

Bさんの戦略

 つづいてBさんは、Aさんが切り取った残りを2つにカットします。もしもBさんにとって、Aさんの最初のカットした分がぴったり3分の1だと思えるなら、あとは「一人が切ってもう一人が選ぶ」手順と同じで、残った3分の2を公平に分ければ、Bさんにとっては、Cさんがどれを選んでも納得のいく分割ということになります。

 もしもBさんにとって、Aさんの最初のカットが3分の1より「少ない」と思う場合も、やはり残りを公平に2つに分ければ、少なくとも自分の取り分はCさんと同じにできますし、Aさんよりも多いと思えるわけです。

 逆に、Aさんの最初のカットが3分の1より「多い」と思う場合は、今度はBさんは最初のAさんのカットした分と同じと思える量だけ、残りからカットすればよいのです。そうすれば仮にCさんが、最初のAさんのカットを選択したとしても、自分が切ったそれと同じ大きさの量を選べます。

Cさんの戦略

 Cさんは最初に選択権がありますから、とにかく自分が一番納得できるものを選べばそれでOKです。


 いかがでしょうか。このように説明されると、公平な方法のように思えませんか。でも、本当に公平でしょうか。(あなたならばAさん、Bさん、Cさんの誰が一番有利だと思いますか?) もっと他の「公平に分ける手順」はあるでしょうか?

(つづく)

<おまけのひとこと>
 日が経つのがはやくて困ります。






1月14日(土) 公平に分ける話(その3)

 ケーキを3人で公平に分けるにはどうしたらいいでしょうか、という話の続きです。二人だったら「一人が切って、もう一人が選ぶ」という方法が有効なのですが、昨日はこれを素朴に3人に適用してみた、「先にカットする人ほど後で選ぶ」という方式を検討してみました。

 この方法について、お二人の方からメールで「問題がある」「この方法のほうがよいのでは」とご提案いただきました。ありがとうございます。

 3人で分ける手順に関しては、古典的な手法がいくつか発表されていて、それを順にご紹介してゆこうと考えていたのですが、いただいたメールを読んで、その前に「公平とは」ということについてすこし議論しておかないといけなかったかなと思いました。今日はその話をしたいと思います。



 さて、というわけで、「公平」ということについて、もうすこしきちんと考えておくことにします。実は、今考えているような「何かを分ける問題」では、分けられたものの相対的な価値は、人によって違っていることがある、ということを前提としています。 たとえば、現金を分配するならば、これはもう金額を3で割ればよいわけで、もちろん端数の1円2円は出るかもしれませんが、分割は機械的にできます。ところがそういった均質ではないものを分けるとき、たとえば「チョコレートケーキとイチゴショートケーキとマロンケーキを3人で1つずつ選ぶ場合」ならば、これは好みの問題が出てきますから、単純ではありません。 このような分割の問題として、象徴的に「ケーキの切り分け」が題材として用いられるのは、ケーキにはいろいろなトッピングなどがあって、単純に量(面積や体積)だけで損得が決まらないからなのだそうです。

 「公平な分割」というのを、「参加者みんなが満足できる」、あるいはもうちょっと控えめに「参加者みんなが不満がなく納得できる」と言い換えましょう。どんなときに不満が出るのか考えてみます。 3人で分ける場合、それぞれの人は自分の取り分が(自分の評価基準で)少なくとも3分の1以上でなければ満足できないでしょう。では、その条件を満たせば満足できるかというと、それだけではだめで、自分の基準で自分の取り分以上の価値のある分け前をもらっている人が他にいると、『あの人の分け前のほうがうらやましい』ということになってしまって、不満足になってしまうのです。

 昨日の「Aさんが3分の1(だとAさんが思う分を)カットして、続いてBさんが残りから全体の3分の1(だとBさんが思う分を)カットして、Cさん、Bさん、Aさんの順に選ぶ」という手順で、Bさんがカットする際、「AさんとCさんに著しい不公平があってもBさんには関係ない」というのが問題ではないか、なぜならそれによって最後に残るAさんの取り分が著しく少なくなってしまうことを抑止する力が働かないから、とご指摘いただきました。

 これは、「自分が(自分の価値尺度で)全体の3分の1以上取れれば、あとの人は多かろうが少なかろうが知ったことではない」という立場かと思います。これは確かに一理あります。しかしここでは、「ともかく、(自分の尺度で)自分以上の分け前をもらう人がいたら不満足」ということで考えたいと思います。

 価値尺度が一定であれば、「他人は自分以上の分け前を受け取っていないと全員が思える状態」は、全員が3分の1ずつの分け前をもらっているときだけです。ところが、価値尺度が一定ではない場合、話は複雑になります。

 誰もが主観的に3分の1以上の分け前をもらっているのに、他人がうらやましくなる例を挙げましょう。さっきの3種類のケーキを例にとります。たとえば、Aさんはイチゴケーキとチョコレートケーキが好きで、Aさんにとっては、この3つのケーキ全体の価値を100とすると、イチゴケーキの価値が50でチョコレートケーキが40、マロンケーキは10だとします。Bさんはイチゴケーキが一番好きで、それ以外はちょっと評価が低い。Cさんはマロンケーキがいちばん好きで、チョコケーキとイチゴケーキはそれなりだとします。

 3人の評価尺度を表にしてみましょう。(横に足すと100になります。)

チョコイチゴマロン
Aさん40%50%10%
Bさん20%60%20%
Cさん30%20%50%

 この場合、Aさんがチョコレートケーキ、Bさんがイチゴケーキ、Cさんがマロンケーキを選ぶのが全体として満足度の和が最大になるのは明らかだと思います。事実これだと3人とも自分の取り分はそれぞれの主観において33%以上あるわけですから、一見文句はないように思えます。

 ところが、このような分配だと面白くないのがAさんです。自分の取り分は自分にとって全体の3分の1以上あるのは間違いないのですが、でもBさんのイチゴショートのほうが、Aさんにとっても価値が高いので、Bさんの分け前のほうがうらやましくなってしまうのです。

 このようなことが起きない、つまり参加者全員が、他の誰の分け前と比べても自分の取り分のほうがよい(もしくは同じ)と思えることを、無羨望(envy-free)な分割と呼ぶそうです。 昨日ご紹介した、「先にカットする人ほど後で選ぶ」という方式は、(N人に一般化できますが)先にカットする人ほど不満足な選択肢が残る可能性があるので、残念ながら公平ではありません。

(つづく)

<おまけのひとこと>
 今日はこれから道祖神のお祭りの「どんどやき」の準備で、朝から子供たちが地区の各家庭を回って、お正月の松飾やわらを集めます。お父さんたちはそれをおおきな「やぐら」に組んで、今夜のどんどやきに備えます。3時からは子供たちは太鼓を叩いて地区の中を練り歩きます。夜は今年が厄年の人が「厄投げ」をして、それから「どんどやき」をやります。・・・と、忙しい一日なのですが、今年は珍しく雨になってしまって、大変です。

 というわけで、今日の更新はあわただしいです。推敲する時間がとれなくて、量はいつもより多いのですがわかりにくい内容になってしまっている気がします。すみません。また、いただいたメールのお返事が書けなくてすみません。






1月15日(日) どんどやき

 すみません今日は単なる日記です。

 昨夜は旧正月の道祖神のお祭りである「どんどやき」でした。昨日は朝9時から子供たちが地域の各戸をまわってお正月の松飾と、燃やすためのわらやかやを集めます。そのときにお祝い金も出していただきます。その間、お父さんたちは集めたわらや竹薮から切ってきた竹などを使って、細長い円錐台のような「やぐら」を作ります。これが午前中いっぱいかかります。

 午後は3時から、小学校の高学年の子供たちが太鼓を叩きながら「村」の中を練り歩きます。今年は雨が降ってしまって大変でした。村の長老と呼ばれる方々も、みな口をそろえて「自分の記憶にある70年、80年の『どんどやき』で、雪ならばともかく雨が降った覚えはない」とおっしゃいます。午後は雨がひどくなって、子供たちと役員さんは大変だったようです。

 どんどやきの「やぐら」は、数十戸の「組」ごとに作るのですが、夕方の放送で、近隣の「組」は軒並み「雨のため翌日に延期」になっていました。うちは連絡がなかったので、ともかく行ってみると、雨も小ぶりだしやってしまおうということになっていました。6時から7時の間に、道祖神さんの前で「厄投げ」がありました。うちの地区は80戸ほどなのですが、毎年だいたい7〜8戸くらいは「厄年」の人のいる家があって、そういう人たちが道祖神さんの前で火を焚いたり、お酒やお米をお供えしたりしてから、みかんやお菓子の小袋やおひねりを投げます。子供たちにとってはとても楽しい行事です。

 7時に6年生がどんどやきのやぐらに点火します。みんな、柳の枝に「繭玉」という餅菓子をつけたものを持って待機しているのですが、最初は火の勢いが強くて、とても近づけません。30分くらいはただずっと火を眺めています。火の粉が高く上がり、とても威勢のよい眺めです。 炎がおさまって真っ赤な炭火になるころ、繭玉をあぶって食べます。今年は雨で気温が高くて、あんまり「どんどやき」という感じがしませんでした。



 今日(日曜日)は、朝は小学校のうさぎ当番に子供を連れて行って、どんどやきの後片付けに行って、さらに「のぼり竿」を倒して収納するという行事がありました。 こういった行事を続けてゆくということは大変なことですが、価値があることだと思います。

<おまけのひとこと>
 疲れがたまっているせいか、午後は昼寝してしまいました。更新も一日お休みです。






[←2005年12月後半]  [↑表紙へ]  [2006年1月後半→]

[Home]-[以前のひとこと]-[2006年1月前半]
mailto:hhase@po10.lcv.ne.jp
2001-2006 hhase