ハト派とタカ派の安定的な比率をC言語で求める
先日、「利己的な遺伝子」を読み終えた。
利己的に振舞う遺伝子が遺伝子プール中に数を増やしていくことが、多くの例から述べられている。他の個体に対して利益を与える行為ですら、自分に返ってくる利益として利己的な行いなのだ。
- 作者: リチャード・ドーキンス,日?敏隆,岸由二,羽田節子,垂水雄二
- 出版社/メーカー: 紀伊國屋書店
- 発売日: 2018/02/15
- メディア: 単行本
- この商品を含むブログ (3件) を見る
nmzfish.hatenablog.com
この記事では、ハト派とタカ派の比率が50対50の場合の平均得点について述べた。本記事では、両者の平均得点が等しくなる比率、つまり、安定的な比率を求めるプログラムをC言語で書く*1。
早速だが、書いたプログラムを以下に示す。
#include <stdio.h> #include <stdlib.h> #include <time.h> int GetRandom(int min, int max); int A,B; int bird[1000] = {}; int main(void){ int i,j,pattern; int hato_hato = 0; int hato_taka = 0; int taka_taka = 0; int taka_all = 500; float taka_total,hato_total = 0; float taka_average,hato_average = 0; for(j = 0; j < 100; j++){ for(i = 0; i < 1000000; i++){ A = GetRandom(0, 999); B = GetRandom(0, 999); if(A <= taka_all && B <= taka_all){ pattern = 0; } if((A <= taka_all && B > taka_all) || (B <= taka_all && A > taka_all)){ pattern = 1; } if(A >= taka_all && B >= taka_all){ pattern = 2; } switch(pattern){ case 0: if(GetRandom(0, 1) == 0){ bird[A] -= 100; bird[B] += 50; taka_taka++; } else{ bird[A] += 50; bird[B] -= 100; taka_taka++; } break; case 1: if(A <= taka_all){ bird[A] += 50; hato_taka++; } if(B <= taka_all){ bird[B] += 50; hato_taka++; } break; case 2: if(GetRandom(0, 1) == 0){ bird[A] += 40; bird[B] -= 10; hato_hato++; } else{ bird[A] -= 10; bird[B] += 40; hato_hato++; } break; }//switch }//for(i) for(i = 0; i <= taka_all; i++){ taka_total += bird[i]; bird[i] = 0; } for(i = (taka_all + 1); i <= 999; i++){ hato_total += bird[i]; bird[i] = 0; } taka_average = taka_total / (taka_all * 1000 * 2); hato_average = hato_total / ((1000 - taka_all) * 1000 * 2); taka_total = 0; hato_total = 0; printf("average of taka equal %f\n",taka_average); printf("average of hato equal %f\n",hato_average); printf("taka all equal %d\n",taka_all); printf("\n"); printf("taka-taka =%d\n",taka_taka); printf("hato-taka =%d\n",hato_taka); printf("hato-hato =%d\n",hato_hato); if(hato_average < taka_average){ taka_all++; } else{ taka_all--; } }//for(j) printf("taka_all = %d\n",taka_all); return 0; } int GetRandom(int max, int min){ static int flag; if(flag == 0){ srand((unsigned int)time(NULL)); flag = 1; } return min + (int)(rand() * (max - min + 1.0) / (1.0 + RAND_MAX)); }
前回の記事からの大きな変更点のみ説明する。
ハト派とタカ派の比率をより正確に求めるため、鳥の数は1000羽とした。
int bird[1000] = {};
前回の記事では乱数を生成し、偶数か奇数かでタカ派かハト派を決定していた。今回は、タカ派の数を決めておき、その数字以下の番号の鳥をタカ派とした。
int taka_all = 500;
対戦形態の判別のための条件式は、以下のようにした。AとBに0~999までの乱数を格納し、それぞれの番号をtaka_allの数と比較することにより、ハト派とタカ派が判別できる。
A = GetRandom(0, 999); B = GetRandom(0, 999); if(A <= taka_all && B <= taka_all){ pattern = 0; } if((A <= taka_all && B > taka_all) || (B <= taka_all && A > taka_all)){ pattern = 1; } if(A >= taka_all && B >= taka_all){ pattern = 2; }
forループの最後で、ハト派とタカ派の1戦辺りの平均得点を計算する。その結果より、タカ派の方が平均得点が高ければタカ派の数が増える。
if(hato_average < taka_average){ taka_all++; } else{ taka_all--; }
jを条件としたforループはタカ派の数を変化させるループである。また、iを条件としたforループは対戦回数である。ループ回数は1000000回であり、鳥が1000羽いることから、それぞれの鳥は2000回対戦を行う。
for(j = 0; j < 100; j++){ for(i = 0; i < 1000000; i++){
出力は以下のようになった。ハト派とタカ派のそれぞれの1戦辺りの平均得点は約6.20~6.30である*2。タカ派の数が583であることから、タカ派の全体に対する比率は約12分の7である。これは著者が計算した結果と等しい。
私たちが用いている任意の得点システムから計算してみると、安定した比率は、ハト派が一二分の五、タカ派が一二分の七となることがわかる。