5ちゃんねる ★スマホ版★ ■掲示板に戻る■ 全部 1- 最新50  

■ このスレッドは過去ログ倉庫に格納されています

【開催】囚人のジレンマ大会

1 :デフォルトの名無しさん:02/04/17 17:48
「囚人のジレンマ」大会をやろうではありませんか。

C言語で「囚人」は関数として作ってください。
1000回取引をし、その合計点数が高い囚人が勝ちとなります。

点数表は以下の通りです。

協調同士 3点
裏切り同士 1 点
協調裏切り 5/0点。

最低得点は1000点。最高得点は5000点になります。

関数は戻り値で 0:協調 か 1:裏切り を返します。
以前の取引は result 配列で参照できます。

メイン関数と囚人関数の例を示します。

#include <stdio.h>


int round;
char result_a[1000], result_b[1000];


int prisoner_a(void) /* 最強しっぺ返し君 */
{
if ( round == 1 ) return 0;
if ( result_b[ round - 1 ] == 0 ) return 1; else return 0;
}

int prisoner_b(void) /* 人間不信裏切り君 */
{
return 1;
}

int main(int argc, char *argv[])
{
int a=0,b=0,pa=0,pb=0;

for ( round = 1; round <= 1000; round ++ ) {
a = prisoner_a();
b = prisoner_b();

if ( ( a == 0 ) && ( b ==0 ) ) { pa+=3;pb+=3; } /* 協調:協調 */
if ( ( a == 1 ) && ( b ==0 ) ) { pa+=5;pb+=0; } /* 裏切り:協調 */
if ( ( a == 0 ) && ( b ==1 ) ) { pa+=0;pb+=5; } /* 協調:裏切り */
if ( ( a == 1 ) && ( b ==1 ) ) { pa+=1;pb+=1; } /* 裏切り:裏切り */

result_a[round] = a;
result_b[round] = b;

printf( "Round %d A:%d / B:%d\n",round,a,b);
}

printf("A:%d / B:%d\n\n",pa,pb);
}

2 :デフォルトの名無しさん:02/04/17 17:50
2げっとずさー

3 :デフォルトの名無しさん:02/04/17 17:54
ttp://google.yahoo.co.jp/bin/query?p=%bc%fc%bf%cd%a4%ce%a5%b8%a5%ec%a5%f3%a5%de%a1%a1C%b8%c0%b8%ec&hc=0&hs=0



4 :デフォルトの名無しさん:02/04/17 17:56
マ板でやってほしかった・・・・・

5 :デフォルトの名無しさん:02/04/17 18:04
しっぺ返しの上を行く戦略があったはずだが。


6 :デフォルトの名無しさん:02/04/17 18:08
>>4 どっちに書くか迷いました。
>>5 しっぺ返し君は万能じゃありません。
上のプログラムの裏切り君には負けます。

7 :デフォルトの名無しさん:02/04/17 19:14
ていうか、これってどういう環境を想定するかによって
最強のアルゴリズムが決まってくるような気がするが。

合計点が「対戦相手より高い」事を「勝ち」とするなら
"人間不信裏切り君" が最強だといえるだろうし、
複数の参加者の総当たり戦の合計点によるものとし、
なおかつその参加者に "協調" を行うものがいることが
予想されれば、"最強しっぺ返し君" が最強(?)という事に
なるのでは。

8 :名古屋在住・中日ファン:02/04/17 19:22
どうでもいいけど
>最低得点は1000点。最高得点は5000点になります。
最低得点は0点でないの?


9 :デフォルトの名無しさん:02/04/17 19:45
私も昔遊んだことがあります。
複数の参加者の総当たり戦の合計点(7 さんが言ってるやつ)を競うなら
このあたりがそこそこ強かったっす。

勝手に opposit て int 型配列を使ってますが
つまり相手側の履歴です。

int prisoner(){
    static int hand = 0; /* 初期は“協調” */

    /* 過去,一度でも裏切られたら二度と協調しない */
    if (round > 1 && opposit[round - 1])
        hand = 1;

    return hand;
}

10 :デフォルトの名無しさん:02/04/17 20:04
しっぺ返し戦略は,他に“DOWNING ”ていう戦略があって
そいつがキングメーカーになってくれてたって話なんだけど
http://darwin.esys.tsukuba.ac.jp/fightsoft/IPD/gameprog-ipd.html
具体的なコード知ってる人いませんかあ?

# でもどうしてこの論文が今更ネット上で読めるですか(泣
#「ゲームプログラミング」買っちゃったっすよ。安くないのに・・

11 :デフォルトの名無しさん:02/04/17 20:14
>>9
「裏切りは許さない」ってタイプですね。
この戦略は「ゴルゴ13アルゴリズム」と命名させてもらいます。

12 :デフォルトの名無しさん:02/04/17 20:14
>>7 おっと、それをわすれていました。ある程度囚人が集まったら、
総当たり戦をやります。

>>8 間違えてました。。。

対しっぺ返し対策は練っておいたほうがいいでしょうね。

int shippe = 0;

if ( round == 1 ) return 1; /* 様子見 */
if ( round == 2 ) return 1;
if ( round == 3 ) return 0;
if ( round == 4 ) return 1;
if ( round == 5 ) return 0;
if ( round == 6 ) return 0;

if ( result_b[1] == 0 )
if ( result_b[2] == 0 )
if ( result_b[3] == 0 )
if ( result_b[4] == 1 )
if ( result_b[5] == 0 )
if ( result_b[6] == 1 )
shippe = 1; /* 相手はしっぺ返しだ! */

if ( shippe == 1 ) return 1;


13 :デフォルトの名無しさん:02/04/17 20:28
>>1
細かい事だが、もうちょいデータ構造とか
関数の形式をよく考えたほうが良かったのでは?
これだけでは皆、自分勝手なコードを書いてくると思われ。

14 :デフォルトの名無しさん:02/04/17 20:32
>>12
/*
if ( round == 1 ) return 1; /* 様子見 */
if ( round == 2 ) return 1;
if ( round == 3 ) return 0;
if ( round == 4 ) return 1;
if ( round == 5 ) return 0;
if ( round == 6 ) return 0;

if ( result_b[1] == 0 )
if ( result_b[2] == 0 )
if ( result_b[3] == 0 )
if ( result_b[4] == 1 )
if ( result_b[5] == 0 )
if ( result_b[6] == 1 )
*/

swichって知ってるか?

15 :デフォルトの名無しさん:02/04/17 20:35
乱数で手を決めるってのは弱いの?

16 :デフォルトの名無しさん:02/04/17 20:39
俺なら、スタックフレームを逆行して、pa,pbを書き換えてやるぜ!

17 :デフォルトの名無しさん:02/04/17 20:59
>>10 こんな感じじゃないでしょうか。

int p=0, q=0;

if ( ( result_a[round-1] == 0 ) && { result_b[round-1] == 0) ) p ++;
if ( ( result_a[round-1] == 1 ) && { result_b[round-1] == 0) ) q ++;

if ( p == q ) return 1;
if ( p > q ) return 0;

return ( round % 2 );

>>13 まあ重要なのは戻り値だけなので。でもさすがプログラム版。的な意見。

>>14 コンパイラががんばってくれることを期待。

>>15 勝率は50%になります。

>>16 エレクトリックサンダー並みの荒技ですね。

18 :デフォルトの名無しさん:02/04/17 21:17
>>17
外部変数を使うプログラムを書かせるのはむちゃだぞ。
判断に必要なデータは全部引数で渡すようにしないと。
13の言うように、ちゃんと関数のインターフェイスを定義するべし。

19 :デフォルトの名無しさん:02/04/17 21:28
早稲田でルール決めて大会を3年前くらいにやって論文発表してた記憶が。

20 :デフォルトの名無しさん:02/04/17 21:39
C房ってどうやっても時代遅れなのね

お前ら頃し合いしてください
http://pc.2ch.net/test/read.cgi/tech/1013093589/

21 :デフォルトの名無しさん:02/04/17 22:08
>>18 まあ現状だと過去の取引結果もいぢり放題なのでデータ捏造できるし、
ちゃんとやるならC++かなんかでクラスでアクセス制御するんでしょうけど、
面倒なので。

とりあえず囚人が集まらないと始まらないので、
ぜひご参加ください。ここにソースを書くと、
後の人がそれを見て対策してしまうので、

prosoners_dilemma@hotmail.com

まで送ってください。スペルは恥ずかしくもミスしました。


22 :デフォルトの名無しさん:02/04/18 01:46
ていうか、人間不信裏切り君は負けることは無いわけですか?

23 :デフォルトの名無しさん:02/04/18 03:17
>>22 するどい。確かに負けません。1点か5点はとれるし、
最高得点である5000点を狙えるのは人間不信裏切り君しかいません。

ただ、ここで微妙なのは、「協調:協調」で
互いに3点ずつとっていくのが現実的にありえそうな最高得点だ、
ということです。

24 :デフォルトの名無しさん:02/04/18 03:22
return rand()%2;

25 :デフォルトの名無しさん:02/04/18 03:28
というか、>>23 を書いて、本から写した5, 3, 1, 0の点数配分が
いまいちなんじゃないか、と思ったり。これでは正直者がバカを見てしまう。

ちなみに「囚人のジレンマ」の場合、最悪のケースは「協調:裏切り」
なのですけど、「裏切り:裏切り」が最悪のケースのゲームは
「チキンゲーム」と言うらしい。です。
そのばあい、より相手の出方を推測しなければなりません。

そっちのほうが面白いかなあ。

26 :デフォルトの名無しさん:02/04/18 03:36
typedef struct tPrison{
  int round;
  char* res_a;
  char* res_b;
}PRISON;

char GetPrisoner(PRISON p);

27 :デフォルトの名無しさん:02/04/18 07:22
ゲームとしては一対一の対戦じゃなりたたないでしょ。
人間不信裏切り君なら負けないわけだし、
そもそも協調するモチベーションもないし。
自分の敵と協調してどないするっていう…。
本来は敵は警察で囚人同士は敵なわけではないのでしょ?
互いに裏切ってばかりだと警察に捕まっちゃうから
囚人同士で協調する必要があるっていう。

やっぱり集団でやって、目標点数に達して無い奴は脱落、
ただし全部のケースで皆が互いに協調した場合、みんな目標点数には届かない。
もちろん互いに裏切りばかりは論外。
出来るだけ協調して点を稼ぎつつも、裏切り:協調で他の囚人を出し抜く必要もある。

そんな感じでやんないとゲームにならんでしょ。

28 :デフォルトの名無しさん:02/04/18 07:53
>ゲームとしては一対一の対戦じゃなりたたないでしょ。
アクセルロッドのやり方知らんの?

29 :デフォルトの名無しさん:02/04/18 11:39
>>27 なので総当り戦でになります。

30 :デフォルトの名無しさん:02/04/18 13:50
ルールがあいまいすぎて大会にならんでしょ。
もっと細かい点まで厳密に決めとかないと。

・激しくがいしゅつの、関数インタフェース
・総当たり戦の結果はどう解釈するのか
-> 各対戦で得られた得点を全て合計して順位をきめるのか
-> それとも単に対戦で勝った数できめるのか
(同じ勝ち数が複数あったらどれを優勝にするのかとか)
・エントリーした関数を主催者側が出場拒否にすることはあるのか

ま〜俺だったら最初の数回だけ特定のパターンを返して、それ以降は全て
裏切りを返す関数を作って応募する。アフォくさいから応募しないけど。

もちろん、相手がその「特定のパターン」を出してきたら以後全て協調
する関数も100種類ほど作って応募する。
(パターン認識に不適合なら完全裏切り)

とりあえず一つの区切りとして、>1は>>50位で削除依頼出して来い

31 :デフォルトの名無しさん:02/04/18 14:05
新規参加者が増えるごとに総当りをやるという理解でいいの?

その場合、現在の対戦順位みたいなものは発表するわけ?

32 :デフォルトの名無しさん:02/04/18 14:24
ルールと仕様は試行錯誤で決めていくのもいいかも。
うまくいかなくてもいいからとりあえず始めない?

対戦に必要なソース修正は1がやるんだよね。(w

前出のコレを読むと、いろいろ議論し始めるとややこしくなりそうな気が。
ていうかその議論が囚人のジレンマ化する罠。
http://darwin.esys.tsukuba.ac.jp/fightsoft/IPD/gameprog-ipd.html



33 :デフォルトの名無しさん:02/04/18 14:31
>>30 すみません、基本的にロバート・アクセルロッドの奴を前提。です。

存じ上げてない方のために書くと、戦略(囚人)は、
自分以外のすべての戦略、自分自身、そして「でたらめ君」と総当り戦を行い、
その得点の合計が高い戦略が勝ち、となります。

主催者側が囚人の「アルゴリズム」によって出場を拒否することは無しに
したいと思います。もちろんアルゴリズム以外の部分では拒否することもあると思いますけど。

34 :デフォルトの名無しさん:02/04/18 14:35
>>31 ある程度集まったらです。僕も1個出すので、
まずは2個、僕以外の誰かが参加していただいたら、
第一回をやりたいと思います。

>>32 はい、わたくしがいたします。

35 :デフォルトの名無しさん:02/04/18 15:07
これってリチャードドーキンスの本のやつ?

36 :デフォルトの名無しさん:02/04/18 15:11
はいそうです。リチャード・ドーキンス本にも載ってましたけど、
僕はウィリアム・パウンドストーンのを。アクセルロッド本は持ってないです。

37 :デフォルトの名無しさん:02/04/18 20:55
>>33
存じ上げてない方のために書くと、戦略(囚人)は、
自分以外のすべての戦略、自分自身、そして「でたらめ君」と総当り戦を行い、
その得点の合計が高い戦略が勝ち、となります。

主催者側が囚人の「アルゴリズム」によって出場を拒否することは無しに
したいと思います。もちろんアルゴリズム以外の部分では拒否することもあると思いますけど。



で、ルールは?

38 :デフォルトの名無しさん:02/04/18 21:07
所詮2chなんだからそんなに厳密な勝負をしても意味がないだろ。

それよりどうせ2chでやるのなら、参加者のソースを隠すのではなく、
スレに書き込まれたソースを定期的に>>1がコンパイルし、
それらの総当たりの計算をやってその結果を公表するって方法が
面白いと思うが、どうよ?
確かに後から書き込んだ奴の方が強いだろうが、それはそれで
対策を練るのが面白くなるだろうし。

39 :デフォルトの名無しさん:02/04/18 23:01
>>37 えーこの時点でルールがわからないとは、キビシイです。

>>38 そうですね。まずは囚人が集まらないと何も始まらないので、ぜひとも。
そのさい囚人に名前を付けてあげてください。
とりあえず僕は「ヒッキー君」を作りました。

40 :デフォルトの名無しさん:02/04/18 23:09
参加したいがルールがわかりにくい。
ちゃんとした日本語にならない?
5/0とかさぁ・・・。

41 :デフォルトの名無しさん:02/04/18 23:23
お前らホフスタッターの
「囚人のジレンマのコンピュータ・トーナメント」
読んでください。


42 :デフォルトの名無しさん:02/04/18 23:38
ソース読んでくださいよ、そもそも「囚人のジレンマ」知っているのですか?
という気持ちを押さえつつ、説明。

囚人が二人います。囚人は別々の独房に入れられていてお互い話が出来ません。
そんな状況の中で看守から「相手を裏切ったらおまえの刑を軽くしてやる」と誘われます。

ここで囚人には「裏切らない(協調)と「裏切り」の二つの選択肢があります。

お互いに「協調」、この場合互いに相手を裏切らず黙秘した場合、
刑期は二人とも2年になります。

一方が裏切り、もう一方が協調した場合、片方は釈放刑期0年、
もう片方は5年となります。

二人とも裏切った場合、刑期は二人とも4年となります。


今回の場合は点数が高いほうが良しとしてあります。

が、囚人のジレンマの説明。


で、もう一度ルールですけど、ラウンドごとに囚人関数は
「0:協調」か「1:裏切り」の戻り値を返します。
result配列によって、過去相手が出した手を参照することが出来ます。

囚人関数同士で総当たり戦を行い、
いちばん総合得点が多い関数が勝ちです。

以上。

43 :デフォルトの名無しさん:02/04/18 23:44
↑得点配分が変だぞ
  協調 裏切
協調3,3  0,5
裏切5,0  1,1
が標準だ

44 :デフォルトの名無しさん:02/04/18 23:46
>>43
>>1 のソースを読んでください。そうなっています。

45 :デフォルトの名無しさん:02/04/18 23:59
自分自身との対戦はあるのですかないのですか?

もしあると状態管理にstatic 変数を使う場合に困ってしまいますが。



46 :デフォルトの名無しさん:02/04/19 00:07
>>45 自分自身との対戦もあります。
逆になぜ困るかが解りません。次スレに static を使った囚人関数
「ヒッキー君」を書きます。

47 :デフォルトの名無しさん:02/04/19 00:07
int prisoner_a( void ) /* ヒッキー君 */
{
static int foo = 0, bar = 0;;

if ( bar = 1 ) {
if ( result_b[round-1] = 0 ) { /* 前回協調したとき相手も協調だったら */
return 1; /* 協調 */
} else {
bar = 0;
return 1; /* じゃなければ引きこもり */
}
}

foo ++;

if ( foo >=10 ) {
foo = 0;
bar = 1;
return 0; /* 10回に1度協調する */
} else { retuen 1; } /* それ以外は引きこもり */
}

48 :デフォルトの名無しさん:02/04/19 00:08
アルゴリズムB:「(前略)くっ・・・・! そうだ・・・・・・・・
今・・・・・・ 大切なことは・・・・相手を信用してみせること・・・
つまり・・・・協調・・・・・!」
アルゴリズムA:「ククク・・・・・ここで、
協調だと・・・・甘い・・・甘すぎる・・・・!
人生(ばっさり後略)」

みたいな囚人のジレンマきぼんぬ。



49 :デフォルトの名無しさん:02/04/19 00:09
> char result_a[1000], result_b[1000];
> for ( round = 1; round <= 1000; round ++ ) {
> result_a[round] = a;
> result_b[round] = b;

こんなことやってるし、
自分が a なのか b なのかわかってないとコード書けないし、
>>1のコードのままだと総当たりやるの大変そうなので
適当に書き直してみました。

こんな感じに書き直して実行してください。

int prisoner_a(int round, int *result_a, int *result_b) /* 最強しっぺ返し君 */
{
if ( round == 0 ) return 0;
if ( result_b[ round - 1 ] == 0 ) return 1; else return 0;
}

int prisoner_b(int round, int *result_a, int *result_b) /* 人間不信裏切り君 */
{
return 1;
}

int hoge(int round, int *own, int *opposite)
{
if ( round == 0 ) return 0;
return (own[round-1] != opposite[round-1]) ? Cooperate : Defect;
}

int random(int round, int *own, int *opposite)
{
return rand()%2;
}

const prisoner_t prisoners[] = {prisoner_a, prisoner_b, hoge, random};

50 :デフォルトの名無しさん:02/04/19 00:11
#include <stdio.h>
#include <stdlib.h>

#define n_elements(a) (sizeof a / sizeof a[0])
#define ROUND 1000

enum {Cooperate, Defect};
typedef int (*prisoner_t)(int round, int *own_result, int *opposite_result);

const prisoner_t prisoners[] = {};

const int n_prisoners = n_elements(prisoners);
int results[n_elements(prisoners)][n_elements(prisoners)];
void print_result(void);

void match(int ia, int ib)
{
int round, a, b, pa=0, pb=0;
static int result_a[1000], result_b[1000];

for ( round = 0; round < ROUND; round ++ ) {
a = prisoners[ia](round, result_a, result_b);
b = prisoners[ib](round, result_b, result_a);

if ( ( a == 0 ) && ( b ==0 ) ) { pa+=3;pb+=3; } /* 協調:協調 */
if ( ( a == 1 ) && ( b ==0 ) ) { pa+=5;pb+=0; } /* 裏切り:協調 */
if ( ( a == 0 ) && ( b ==1 ) ) { pa+=0;pb+=5; } /* 協調:裏切り */
if ( ( a == 1 ) && ( b ==1 ) ) { pa+=1;pb+=1; } /* 裏切り:裏切り */

result_a[round] = a;
result_b[round] = b;
}

results[ia][ib] = pa;
results[ib][ia] = pb;
}

int main(void)
{
int i, j;

for ( i = 0; i < n_prisoners; i++ )
for ( j = i; j < n_prisoners; j++ )
match(i, j);

print_result();

return 0;
}

51 :デフォルトの名無しさん:02/04/19 00:11
void print_result(void)
{
int i, j, sum;

printf(" ");
for ( j = 0; j < n_prisoners; j++ )
printf("%5d" ,j);
printf(" sum\n");

for ( i = 0; i < n_prisoners; i++ ) {
sum = 0;
printf("%2d", i);
for ( j = 0; j < n_prisoners; j++ ) {
printf("%5d", results[i][j]);
sum += results[i][j];
}
printf("%6d\n", sum);
}
}

52 :51の半角スペースが消えたので訂正:02/04/19 00:17
void print_result(void)
{
int i, j, sum;

printf("  ");
for ( j = 0; j < n_prisoners; j++ )
printf("%5d" ,j);
printf("   sum\n");

for ( i = 0; i < n_prisoners; i++ ) {
sum = 0;
printf("%2d", i);
for ( j = 0; j < n_prisoners; j++ ) {
printf("%5d", results[i][j]);
sum += results[i][j];
}
printf("%6d\n", sum);
}
}

53 :デフォルトの名無しさん:02/04/19 00:19
>>49-51 さすがム板。ソース書き換えるのが面倒だなあ、
と思い始めていた頃でした。多謝。

54 :デフォルトの名無しさん:02/04/19 00:21
私の理解が間違ってるのかもしれませんが、最強しっぺ返し君の論理判定は
逆では?

55 :デフォルトの名無しさん:02/04/19 00:30
>>54 ガーソ! その通り。です。
これじゃあ「ひねくれあまのじゃく君」ですね。失敗失敗。

56 :デフォルトの名無しさん:02/04/19 01:02
大会は総当たりを一回やって得点の一番高かった囚人が優勝なの?
それだと人間不信裏切り君にいっぱい点をやるバカが
いっぱいエントリーしてたら人間不信裏切り君が優勝しちゃうよね?
そんなことの無いように予選-決勝にする?
そのへんどうすんのよ?

57 :30:02/04/19 01:38
>>56 >>30で突っ込み済み。

それの対策が
『主催者側が囚人の「アルゴリズム」によって出場を拒否することは無しに
したいと思います。もちろんアルゴリズム以外の部分では拒否することもあると思いますけど。』

ただしこんなあいまいな表現では、主催者側の気分次第(ハンドルがむかつく
とか)で何ら問題のないエントリーも出場拒否される恐れもある諸刃の剣。

58 :デフォルトの名無しさん:02/04/19 02:21
ちょっと試してみたんですが、ヒッキーくんは大会を盛り上げるには
とてもよいキャラクタですね。参加者の顔ぶれによってかなり
得点が上下するし優勝する可能性もある。

ところで、最初の return はコメントと逆な気がしますが
どちらでしょう? こちらで試した範囲ではソース通りの
ほうが強いみたいです。

59 :デフォルトの名無しさん:02/04/19 02:28
乱数は、全員に同じ乱数列を渡したいなぁ。

60 :デフォルトの名無しさん:02/04/19 02:34
OOの継承使えば、もっとエレガントなコードになると思うが。。。
>>1は責任もって、OOの(以下略

61 :デフォルトの名無しさん:02/04/19 03:10
CDilemma{
public:
  char *m_History;

  virtual bool GetDilemma();
  static int main();
}

以下実装をおながいします。

62 :デフォルトの名無しさん:02/04/19 03:14
>>60
つかエレガントさを競う必要ないのだし
>>49-52でいいんじゃないのか?

63 :デフォルトの名無しさん:02/04/19 07:10
>>42
知らないから聞いているんですが何か?
素人は参加しちゃいけないのね。じゃあMLでも立ち上げてやれば?


64 :デフォルトの名無しさん:02/04/19 07:40
>>62
実際に対戦させる人間の事を考えてみれ。現状だと戦略が2つ提示されたとして、
それを対戦させる為の(>>50のmatch()みたいな)コードを1本書かなくてはならない。
1000件を総当たりさせるときの手間はどうなる事やら・・・

まあ、文句をつけるだけなら誰でも出来るって言われそうなので、一応俺も提案してみる。

int StorategyFoo/*ユニークな名前*/(
    int round /* 対戦の順目 */,
    const int self[] /* 自分の前回までの行動履歴(round-1個まで)*/,
    const int enemy[] /* 敵の前回までの行動履歴(round-1個まで)*/ );
返り値: 0:協調 1:裏切り
*履歴は関数を呼び出す側が書き込むものとする

こんなんであれば、とりあえず不満は出ないのでは?

行動履歴の配列をグローバルで result_a とか result_b とかにすると、
関数側では自分はどちらの配列を使えばいいか判断できないからダメダメだと思うが。

65 :デフォルトの名無しさん:02/04/19 10:53
>>63
つーか、結構有名な問題だと思うが。<囚人
その程度のことも調べられずに参加しようって方が間違い。
逆ギレするのは勝手だが、素人なりにできる事はあるだろが。
わからなかったらまず調べろ。


66 :デフォルトの名無しさん:02/04/19 12:47
>>63 そういうことをよく恥ずかしくもなく書けるね。まあ匿名掲示板だからな。
>>64 >>49-52 のプログラムがなにやってるのか理解できないのですか?!

67 :デフォルトの名無しさん:02/04/19 12:49
>>49-52 ご苦労様。
とりあえず対戦環境もできたので一つ投稿します。

10, 17 で紹介されていた DOWNING を改良してみました。
名前は DW+ です。

挙動不審なところもあるけどご愛嬌ということで。


/* DOWNING 改良版 DW+ */

#define FIRST_ROUND 0

int prisoner_dwplus(int round, int *result_a, int *result_b) {
static int p,q, flag, count_d;

if ( round == FIRST_ROUND ) {
p=q=0;
flag = 0;
count_d = 0;

return 0; /* オリジナルの欠点を修正 */
}

if ( round > FIRST_ROUND ) {
if ( ( result_b[ round - 1 ] == 0 ) && ( result_a[ round - 1 ] == 0 ) ) {
p++;
} else if ( ( result_b[ round - 1 ] == 1 ) && ( result_a[ round - 1 ] == 0 ) ) {
q++;
}

}

/* 人間不信裏切り君対策 */
if ( flag ) return 1;

if ( ( round > FIRST_ROUND ) && ( round < FIRST_ROUND + 10 ) && ( result_b[ round - 1 ] == 1 ) ) {
count_d++;
if ( ( round == FIRST_ROUND + 9 ) && ( count_d > 8 ) ) flag = -1;
}

/* オリジナルの判定部 */
if ( p == q ) {
return 1;
} else if ( p > q ) {
return 0;
} else {
return round % 2;
}
}


68 :デフォルトの名無しさん:02/04/19 19:58





































69 :デフォルトの名無しさん:02/04/19 23:31
良スレ上げ

70 :デフォルトの名無しさん:02/04/19 23:38
Delphiバージョン。やっぱクラスの方が楽だね。

// しっぺ返し
procedure TRevengePrisoner.Execute;
begin
Cooporate(Turn = 1);
CorD(Enemy[-1]);
end;

// 天邪鬼
procedure TPerversePrisoner;
begin
Defect(Turn = 1);
DorC(Enemy[-1]);
end;

// 寛容(1回まで)
procedure TTrelantPrisoner.Execute;
begin
Cooporate(Turn = 1);
CorD(Enemy[-1] or Enemy[-2]);
end;

71 :デフォルトの名無しさん:02/04/20 16:21
>>58 逆でした。。。

72 :デフォルトの名無しさん:02/04/20 16:30
おまっとさんでした。第一回囚人のジレンマ大会を開催いたしました。
今回のエントリーは、

0. 最強しっぺ返し君
1. 人間不信裏切り君
2. ゴルゴ13
3. hoge
4. random
5. DOWNING 改良版 DW+
6. ヒッキー君

の7囚人でした。

73 :デフォルトの名無しさん:02/04/20 16:35
大会ソース

http://www.geocities.co.jp//SilkRoad-Ocean/5567/prisoner2.c.txt

74 :デフォルトの名無しさん:02/04/20 16:43
で、結果発表です。

0 1 2 3 4 5 6 sum
0 3000 999 3000 2667 2498 3000 999 16163
1 1004 1000 1008 5000 3000 1020 1000 13032
2 3000 998 1000 5000 3000 1020 1000 15018
3 2667 0 0 1002 2250 8 0 5927
4 2503 500 500 2250 5000 507 500 11760
5 3000 995 995 4993 2997 3000 995 16975
6 1004 1000 1000 5000 3000 1020 1000 13024

第一回の優勝囚人関数は「DOWNING 改良版 DW+」でした。
2位 最強しっぺ返し君
3位 ゴルゴ13

でした。

最後にもう一度、>>49-52 さんに感謝。

# えーっと、この結果で間違ってないんだよな。

75 :DW+:02/04/20 17:08
おっ、予想外の健闘か と思ったら、ゴルゴ13 は対戦相手が変わっても
引きこもったままになるので、下のように変えたほうがいいかも

int golgo13( int round, int *result_a, int *result_b ){ /* ゴルゴ13 */
static int hand = 0; /* 初期は“協調” */

/* 初期化を追加 */
if ( round == FIRST_ROUND ) hand = 0;

/* 過去,一度でも裏切られたら二度と協調しない */

/* 初回ラウンドが0からになったので修正 */
if (round > FIRST_ROUND && result_b[round - 1])
hand = 1;

return hand;
}



76 :DW+:02/04/20 17:11
あっ初期化はこのほうがいいか。
if ( round <= FIRST_ROUND ) hand = 0;

77 :DW+:02/04/20 17:22
見にくくなったので書き直してみた。

int golgo13(int round, int *own, int *opposite)
{
static int hand = Cooperate;

if ( round <= FIRST_ROUND ) hand = Cooperate;
else if ( opposite[round-1] == 1 ) hand = Defect;

return hand;
}

78 :デフォルトの名無しさん:02/04/20 17:40
とてもすみません。かなーり重大なミスをしてしまっています。

1. ヒッキー君の「等価判断」式が「代入」になっている。== が = ってこと。

まあ別にこれはいいのですけど、ヒッキー君同士がたたかうと4991点とれるはずなんですけど、
とれてません。それは static を使っているからで。
ゴルゴ13とDW+もおそらく誤動作しています。

すみません、関数のほうで何とかします。してください。


79 :DW+:02/04/20 17:58
DW+は自己対戦の場合、先手・後手とも3000点なので static 変数の影響
は無視できてます。他の戦略も自己対戦の成績が3000点なら普通は問題
ないはず。

ただ今後自己対戦の時に先手と後手で手を変えるような戦略が出てくると
思うのでこの場合は最高点の5000点近く取れますから、これを認めるか
どうかをルールとして決めたほうがいいと思います。




80 :デフォルトの名無しさん:02/04/20 18:05
>>16

このスレそのものが囚人のジレンマだな

81 :DW+:02/04/20 18:07
>>78
>ヒッキー君同士がたたかうと4991点とれるはずなんですけど

最高点の5000点近くを出すと相手は0点近くなると思います。

82 :デフォルトの名無しさん:02/04/20 18:08
>>78 さらにすみません、4991点ではなく2982点でした。。。

83 :デフォルトの名無しさん:02/04/20 18:09
>先手と後手で手を変えるような戦略が出てくると
同時に指すんだから先手とか後手とかAとかBなんてナンセンス
自分と相手でコード書けるようにしとけ

84 :デフォルトの名無しさん:02/04/20 18:31
>>79 いやフラグ。とか。

85 :DW+:02/04/20 18:33
先手・後手というのはあくまで現在の対戦プログラムでの話なのよ。

厳密なルールで戦っているわけではないから指摘しただけ。


86 :デフォルトの名無しさん:02/04/20 18:35
非常に泥臭いですが、対策しました。

囚人関数のの引数は

typedef int (*prisoner_t)(int round, int *own_result, int *opposite_result, int who);

となり、最後の引数に int who を追加しました。呼び出すさいには

a = prisoners[ia](round, result_a, result_b, 0);
b = prisoners[ib](round, result_b, result_a, 1);

とするので、関数側で、例えば配列でなんとかしてください。
あと、match 関数の初回で、

prisoners[ia](0, 0, 0, 3);
prisoners[ib](0, 0, 0, 3);

と who に 3 を渡して呼び出します。これをトリガーに初期化してください。

非常に泥臭くてすみません。

87 :デフォルトの名無しさん:02/04/20 18:36
対策版「ヒッキー君」

int hikkie( int round, int *own, int *opposite, int who ) /* ヒッキー君 */
{
static int foo[2] = { 0, 0 };

if ( who == 3 ) {
foo[ 0 ] = 0;
foo[ 1 ] = 0;
return 0;
}

if ( foo[ who ] == 1 ) {
if ( opposite[ round - 1 ] == 0 ) { /* 前回協調したとき相手も協調だったら */
return 0; /* 協調 */
} else {
foo[ who ] = 0;
return 1; /* じゃなければ引きこもり */
}
}

printf( "%d\n", round % 10 );

if ( ( round % 10 ) == 0 ) {
foo[ who ] = 1;
return 0; /* 10回に1度協調する */
} else { return 1; } /* それ以外は引きこもり */
}


88 :デフォルトの名無しさん:02/04/20 18:38
>>79 自己対戦で5000点取れるのは認めます。
相手は0点なので。

というか、自己対戦で3000点近く取れるようにするのは必須になるでしょう。と。

# あー頭が回ってないなあ。つまらないミスばかりだ。

89 :デフォルトの名無しさん:02/04/20 18:47
>自己対戦で5000点取れるのは認めます。
>相手は0点なので。
ふと思ったんだけどその「相手」って「自己」なわけだから
どっちの点数が採用されるの?

90 :DW+:02/04/20 19:07
現在の対戦プログラムだと後手(下の関数)の得点です。

91 :DW+:02/04/20 19:30
>自己対戦で5000点取れるのは認めます。

よく考えたらこれだとこの対策の実装は必須となり、どの戦略も5000点取るよう
になってしまいますね。相手が自分であることを判定するコストはそれほど
ないので差が出ないと思います。

自己対戦は点数の低い方にしませんか?

自己対戦で 3000点がとれないプログラムはどの道対策は必要ですし。



92 :DW+:02/04/20 19:31
どの戦略も5000点は 5000点近くです。訂正。

93 :デフォルトの名無しさん:02/04/20 19:41
>>88 さらに勘違いしてしまってすみません。
自己対戦で相手が0点でも後手の点数が採用されるなら
協調して互いに3000点とるより5000点取らないと意味ないですね。

>>91 いや、相手が自分自身であることを判定するのは
それなりのアルゴリズムが必要なんじゃないでしょうか。
最初の10ラウンドをマジックコードとして、って判定できますけど、
それを偽装囚人も現れるでしょうし。

94 :デフォルトの名無しさん:02/04/20 19:45
現在ちょっと悩んでいるのは「でたらめ君」で、
>>73 のソースだとシードの関係か、
自己対戦の場合0点か5000点になります。で、

int _random(int round, int *own, int *opposite)
{
srand((unsigned)(time(NULL)%(round+1)));
return rand()%2;
}

見たくしてみたんですけど、毎回同じ囚人の総合得点の
結果でも2000点ぐらい差が出ます。こうなると順位が入れ替わってしまうので、
大会をさらに1000回やってその平均、とかなると面倒だなあ、
rand関数使うの禁止、にしようかなあ、とか考えますけどどうでしょうか?



95 :デフォルトの名無しさん:02/04/20 19:53
とりあえず自己対戦対処した大会ソース(でたらめ君抜き版)

http://www.geocities.co.jp//SilkRoad-Ocean/5567/prisoner3.c.txt

第二回大会

0. 最強しっぺ返し君
1. 人間不信裏切り君
2. ゴルゴ13
3. hoge
4. DOWNING 改良版 DW+
5. ヒッキー君

0 1 2 3 4 5 sum
0 3000 999 3000 2667 999 1300 11965
1 1004 1000 1004 5000 1000 1400 10408
2 3000 999 3000 4993 999 1399 14390
3 2667 0 8 1002 0 795 4472
4 1004 1000 1004 5000 1000 1400 10408
5 1300 900 904 4305 900 2982 11291

優勝 ゴルゴ13
2位 最強しっぺ返し君
3位 ヒッキー君

# おそらく。自分の頭の悪さに逝ってきます。。。

96 :デフォルトの名無しさん:02/04/20 19:59
              


















97 :デフォルトの名無しさん:02/04/20 20:08
>>68 >>96>>63

98 :DW+:02/04/20 20:14
main に randomize(); を入れて乱数を初期化しましょう。

>>80 わかってはいるんだけどね。

99 :DW+:02/04/20 21:11
>>93
相手の手だけから判定するならそれなりのアルゴリズムが必要ですが、
static変数を使えば少なくとも第2ターンの後手で判定可能になります。

今のルールだと初期化ターンと先手後手の情報が追加されたので
第1ターンの先手で自己対戦であるとわかりますから5000点ゲット可能です。

戦略変更を認めるなら static変数で自分かどうか判定するのを禁止する必要が
あると思います。

ソースの修正とかややこしくなるので、対戦プログラム自体をルールに合うように
改良するまで自己対戦にはこだわらないほうがいいかも。

>最初の10ラウンドをマジックコードとして、って判定できますけど、
>それを偽装囚人も現れるでしょうし。

最終的にはそういう高度な対戦になっていけばいいなと思っています。
1000ターン1マッチでなく、 100ターン * 10マッチみたいな形式なら
相手の出方をデータベース化して後半が本当の勝負みたいなことも
やれるかもしれません。




100 :デフォルトの名無しさん:02/04/20 21:55
協調性の高い囚人が多そうなので…

#ifdef __cplusplus
#define UNDEF(x) int act_##x (int round, const Result& own, const Result& opposite,int who)
#define ALIAS(x,y) Prisoner<act_##x> y(#y)
#define DEF(x) UNDEF(x);ALIAS(x,x);UNDEF(x)
#define PREV (-1)
#else
#define DEF(x) int x (int round, const char* own, const char* opposite, int who )
#define PREV (round-1)
#endif

DEF(lastpoo){ /* 最後っぺ野郎 */
#ifdef ROUND /* 参照可能なら… */
if ( who == 3 ) return 0;
if ( round == ROUND-1 ) return Defect;

#else /* 同じ相手とは連続して戦うことが条件 */
static int p=0, flag=0;
if ( who == 3 ) return 0;
if ( flag < 2 || round < p ) flag++;
if ( flag < 3) p = round;
else if ( round == p ) return Defect;
#endif
/* 実はゴルゴ君 */
if ( round == FIRST_ROUND ) return Cooperate;
return own[PREV] != opposite[PREV] ? Defect: opposite[PREV];
}

101 :DW+:02/04/20 22:02
>>99 static変数を使えば少なくとも第2ターンの後手で判定可能になります。
いかん久しぶりに頭使ったのでボケてた。第1ターンの先手、最初から分かるわ。

俺も逝ってくる。

102 :100:02/04/20 22:12
>>100 対戦回数の判定部分は、先手後手がはっきりするんだから、
もっとすっきり書けるはずなんだね。
とりあえず、int who だけ対処したもので…(^^;

…囚人番号100番、脱走しました!

103 :デフォルトの名無しさん:02/04/20 22:48
何ラウンドやるかは参照不可能にしとかないとまずそうだね。

104 :デフォルトの名無しさん:02/04/20 23:57
“次回もラウンドが継続する確率 w”を与えるってルール
面白そうっすね。
>>10>>32 で URL を示した論文に書かれてあるコトなんだけど。
# でもこれを戦略に取り入れようとした途端に
# コード書くのが面倒くさくなるという罠。笑い

105 :デフォルトの名無しさん:02/04/21 02:36
>>103 >>104
それは「ラウンドが長いと囚人が『進化(?)』する」からってことですか?

106 :デフォルトの名無しさん:02/04/21 02:39
なんかコードがどんどん変わってるみたいだが、今は一体どれでやってんの?

107 :デフォルトの名無しさん:02/04/21 02:42
>>106 それは >>95 の。

108 :デフォルトの名無しさん:02/04/21 02:44
>105
ちゃう。
ターン数が分かってると最後に限って裏切る奴が出てきちゃうから。
囚人ゲームが日常の人間関係を模してるとするなら
最終ターンって地球滅亡の最後の日のことで
それが分かってしまうと一気に日常的じゃなくなってしまう。

プレイはーはあくまで永遠に日常が続くという前提でプレイすべき。
# そういう意味では最初のターンの行動はランダムにしてみるのも良いかも。
# ランダムじゃまずいかな?よくわからん。

109 :デフォルトの名無しさん:02/04/21 02:51
>>108
例えば最後の10ラウンドだけ裏切るようにしても、
それは全体にはあまり影響ない(合っても最大50点)だし、
他の囚人はその対策すればいいだけ。

110 :デフォルトの名無しさん:02/04/21 03:12
if (round == ROUND) /* ... */ ;

みんながこんな例外処理をしなきゃいけないのはちょっとアレやね。

111 :デフォルトの名無しさん:02/04/21 03:25
int 偽善君( int round, int *own, int *opposite )
{
if ( round < 999 ) return 0;
return 1;
}

112 :デフォルトの名無しさん:02/04/21 04:08
>>111
ワラタ

113 :デフォルトの名無しさん:02/04/21 04:39
*
傷つけられたプライドは10倍にして返すのよ、
ヤマアラシのジレンマ、でもあたしを見てぇーさん
*/
int aska( int round, int *own, int *opposite, int who )
{
static int foo = 0, bar = 0, coo = 0, AreYouMe = 0;

if ( who == 3 ) { foo ++; return 0; }
if ( foo == 2 ) AreYouMe = 1;
if ( who != 3 ) foo = 0;

if ( AreYouMe == 1 ) return 0; /* 自分とは仲良し。誰もあたしのことを解ってくれない。 */

if ( round == 0 ) return 1; /* 「あんたバカぁ?」と先制攻撃 */

if ( opposite[ round - 1 ] == 0 )
if ( opposite[ round - 2 ] == 0 )
if ( opposite[ round - 3 ] == 0 )
if ( opposite[ round - 4 ] == 0 )
bar = bar + 5; /* 近寄られると反発 */

if ( opposite[ round - 1 ] == 1 )
if ( opposite[ round - 2 ] == 1 )
if ( opposite[ round - 3 ] == 1 )
if ( opposite[ round - 4 ] == 1 )
bar = bar - 20; /* 相手にしてもらえないと「あたしを見てぇ!」 */

if ( opposite[ round - 1 ] == 1 ) bar = bar + 10; /* 敏感に反応。10倍返し */

if ( bar > 0 ) { bar --; return 1; }

return 0;
}

114 :デフォルトの名無しさん:02/04/21 05:07
// われは全痴全脳の神
int yhwh( int round, int *own, int *opposite, int who )
{
  return(round % 2);
}

115 :デフォルトの名無しさん:02/04/21 11:52
>>108
やっぱラウンド数はランダムな方法で決めて、各囚人プログラムには
いつゲームが終了するのかわからないようにしないといけないと
思うな。

116 :デフォルトの名無しさん:02/04/21 14:02
いっそ、ターン数だけでなくて、対戦相手が特定できて、
それまでの成績とかまでわかるほうが楽しそう。

117 :デフォルトの名無しさん:02/04/21 14:40
>>115 それはどうして?

>>116 相手の特定はシステムで提供するのではなく自身のアルゴリズムで
やったほうが腕の見せ所があるし、成績情報を提供するのはどうかなあ。

118 :デフォルトの名無しさん:02/04/21 19:21
>>117
>>108 にも書いてるけど、ラウンド数がわかってたら
途中まで協調してきたとして、最後の最後で裏切れば
相手より得点が高くなるわけで、ゲームとしての
選択肢の意味が薄れるというか。

そこらへんは↓の論文をよく読んで欲しい。
http://darwin.esys.tsukuba.ac.jp/fightsoft/IPD/gameprog-ipd.html

119 :デフォルトの名無しさん:02/04/21 20:41





















120 :DW+:02/04/21 21:47
遅くなりましたが第2回大会用にソースを合わせました。
アルゴリズム等は第1回用と同じです。

DOWNING 改良版としていましたが結果的にオリジナルのDOWNINGとは
性格が変わってしまったのでDOWNING 改変版にかえます。





121 :DW+:02/04/21 21:51

int prisoner_dwplus(int round, int *own, int *opposite, int who ) /* DOWNING 改変版 DW+ */
{
    static int p[2], q[2], flag[2], count_d[2];

    /* 初期化ターンの処理 */
    if ( who == 3 ) {
        p[0] = p[1] = 0;
        q[0] = q[1] = 0;
        flag[0] = flag[1] =0;
        count_d[0] = count_d[1] = 0;

        return Cooperate;

    }

    /* 初回ターンはとりあえず協調 オリジナルはまず裏切りだった */
    if ( round <= FIRST_ROUND ) return Cooperate;


    /* 相手の出方を観察する */
    if ( round > FIRST_ROUND ) {
        if ( ( opposite[ round - 1 ] == Cooperate ) && ( own[ round - 1 ] == Cooperate ) ) {
            p[who]++;
        } else if ( ( opposite[ round - 1 ] == Defect ) && ( own[ round - 1 ] == Cooperate ) ) {
            q[who]++;
        }
    }

    /* 人間不信裏切り君に弱くなったので対策 */
    if ( flag[who] ) return Defect;

    if ( ( round > FIRST_ROUND ) && ( round < FIRST_ROUND + 10 ) && ( opposite[ round - 1 ] == 1 ) ) {
        count_d[who]++;

        if ( ( round == FIRST_ROUND + 9 ) && ( count_d[who] > 8 ) )
            flag[who] = -1; /* 人間不信裏切り君 ハケン!( ̄ー+ ̄)キラーン */
    }

    /* オリジナルの判定部 */
    if ( p[who] == q[who] ) {
        return Defect;
    } else if ( p[who] > q[who] ) {
        return Cooperate;
    } else {
        return ( (round % 2 ) == 0)? Cooperate : Defect;
    }
}

122 :いっそ思考過程を表示しちゃうってのはどうよ?:02/04/21 22:00
/* 思考過程を表示 */
void talk(const char *format, ...);

例:
if ( ( round == FIRST_ROUND + 9 ) && ( count_d[who] > 8 ) ){
  talk("人間不信裏切り君 ハケン!( ̄ー+ ̄)キラーン ");
  flag[who] = -1;
}


123 :デフォルトの名無しさん:02/04/21 22:19
>>122
お、それ面白いな。端末で対戦模様を見たらそういうのが
流れるわけね。でも何万回も見たら死ぬかも(笑

124 :デフォルトの名無しさん:02/04/21 22:26

/* 普通の人? */
int shomin(int round, int *own, int *opposite, int who )
{
return (round ==0) ? Cooperate:
own[round-1] != opposite[round-1] ? Defect: Cooperate;
}

実は特殊な才能を持ち合わせてるんだなこれが…



















































125 :デフォルトの名無しさん:02/04/21 22:57
>>122,123
そういう意味で、ヒッキー君とアスカ(aska)ちゃんの組合せが面白い。
ヒッキー君が態度を変えるのにあわせて、アスカの感情の起伏が激しい。
最終的な機嫌(barの値)は32。スコア自体は、1963-1638 でヒッキー君の勝ち。
他の対戦者とは大体、±4桁だから相性のよさ?が見て取れる。

ほんとはアスカ同士、最強しっぺ返し君のほうが barの値は小さかったけど、
アスカは自分自身を見分けるし、最強しっぺ返し君とはパターンが一定のやりとりなので、
よりランダム性の高いヒッキー君をベストパートナーに選びました。

# askaのコードは少し手を加えてたので、公式の結果とはいえません。あしからず

126 :デフォルトの名無しさん:02/04/21 23:58
良スレ上げ

127 :デフォルトの名無しさん:02/04/22 00:44
> しかし、対戦回数を固定しておくと、最終回(その後はない、
> つまり世界は終末を迎える)は1回きりの対戦と同じだから、そこでは裏切り
> に決まってしまう。すると最終回の一つ手前も裏切るべきで、数学的帰納法に
> より、全回裏切りが適当、となってしまう。

んなこたぁーない。

128 :デフォルトの名無しさん:02/04/22 00:51
どうもその筑波大のやり方は気に入らない。
のは、「自分自身とは対戦しない」ところと
「通信路や得点に」ノイズを入れるところ。

このゲームの本質がぼやけてしまうではないか。

という点では、 aska の自己判断もいまいちだったかも。
あくまで result から判断すべき。か?

129 :デフォルトの名無しさん:02/04/22 00:59
>>128
ノイズを入れるってのはリアリティを高めるためだろうが、
純粋にゲームとして見るならなくてもOKだろうな。
だが、ラウンド数を不定にするのは賛成だ。

130 :デフォルトの名無しさん:02/04/22 01:13
ノイズに関しては、これが人工生命のシミュレーション、
例えば Tierra なら賛成だけど、これはシミュレーションじゃないし。

>>129 そのラウンド数を不定にするのはどの範囲で? 1000±300 とか?

131 :デフォルトの名無しさん :02/04/22 01:27
自分で配列をもつ囚人のためにターン数の上限だけはわかるように
したほうがいいね。実際はそれから類推できないぐらい少ないターン数
ということで。

132 :デフォルトの名無しさん:02/04/22 01:40
> 1回きりの対戦と同じだから、そこでは裏切りに決まってしまう。

この論理が間違い。なぜ裏切りに決まるんだYO!
裏切りだと期待値が3.0、だけど協調でも3.0だYO!

133 :デフォルトの名無しさん:02/04/22 01:44
>>130
先の論文にもあったが、次のラウンドが存在する確率を設けておいて
ラウンドごとに判定すればいいと思う。確率は0.999ぐらいかな?
この値も不定にするらしいけど。
つまり、どれぐらいラウンドが続くかまったく不明にしておかないと
ラウンド数に依存した囚人ができてしまってつまらないってこと
だろうな。

>>131
不定長配列を作ってもらえばサイズは不定でもかまわないと思うけど、
どうかな?

134 :デフォルトの名無しさん:02/04/22 01:46
>>132
期待値って言い方が適切かどうか置いておいて、協調の場合の
その「期待値」は1.5だよね?あきらかに裏切り有利。

135 :デフォルトの名無しさん:02/04/22 01:53
>>134 おおう!よく考えたらそうでした。逝ってきます。。。

136 :デフォルトの名無しさん:02/04/22 02:31
横から。

対戦回数が1000回だとして、
「対戦回数が固定されていることを利用した戦略」例を示して欲しい。

137 :デフォルトの名無しさん:02/04/22 04:52
>>100 lastpoo 最後に出し抜くパターン
>>111 偽善君 最後だけ仲良くするパターン

138 :デフォルトの名無しさん:02/04/22 05:02
>>137 最後だけ数点稼いで何の意味があるのでしょうか?

ちなみに偽善君は最後は「裏切り」。

139 :DW+:02/04/22 08:22
>ちなみに偽善君は最後は「裏切り」。
ゴメン、こちらの勘違い。最後だけいい顔するから偽善だと思った。

>最後だけ数点稼いで何の意味があるのでしょうか?
こちらの手に対して敏感に手を変える相手との対戦ではこちらが裏切ると
相手も裏切り返すので戦争状態になりやすい。こういう相手とは協調して
3点ずつをとるのが一番いい戦術ですよね。しっぺ返し君やゴルゴ13のような
敏感な戦術が上位になるのはある程度予想できるので、上位の戦略同士の
対戦は3点×ラウンド数の引き分けが多いはず。たとえ1点でも上位の相手を
上回れるんだから、必死で勝とうとするならやるしかないと思う。

特にここだとソースを公開しているので、ライバルが最後に裏切るように
なっていれば対抗上こちらも裏切るしかない。あとは>>127 で引用されて
いるのと同じで、ソースを発表するごとに裏切るターンが早くなっていく。

今のところ囚人の個性が豊かでそれほど問題になってないけど。


最終ラウンドの裏切りや対戦相手ごとに戦術を調整するバージョンを作って
みたのでこの後にアップします。


140 :137 = DW+:02/04/22 08:27

キャラクタ別の戦略を増やしました。名前はいいのが思いつかない
からとりあえず DW+2 です。

悪乗りして >>122 の思考過程表示を簡易実装して
メッセージを表示します。
askaちゃんから貢いでもらえるのでかなりの得点が出ます。
最終ラウンドにそれまで協調していた相手を裏切ります。

見にくいのでインデントを入れますが、不要なら以後入れません
ので指摘してください。



/* メッセージ表示 */
#define TALKING

void talk( int who, char *mes )
{
#ifdef TALKING
printf("[ %d ] %s\n", who, mes);
#endif

}

141 :137 = DW+:02/04/22 08:28
int prisoner_dwplus2(int round, int *own, int *opposite, int who ) /* DW+2 */
{
    static int p[2], q[2], flag[2], count_d[2], poo[2];

    /* 初期化ターンの処理 */
    if ( who == 3 ) {
        int i;
        for ( i = 0; i < 2; i++ ) {
            p[i]=q[i]=flag[i]= 0;
            count_d[i] = 0;
        
            poo[i] = 1;
}
        return Cooperate;
    }

    /* 初回ターンはとりあえず協調 */
    if ( round <= FIRST_ROUND ) return Cooperate;


    /* 2ターン目以後の処理 */

    /* 相手の出方を観察する */
    if ( ( opposite[ round - 1 ] == Cooperate ) && ( own[ round - 1 ] == Cooperate ) ) {
        p[who]++;
    } else if ( ( opposite[ round - 1 ] == Defect ) && ( own[ round - 1 ] == Cooperate ) ) {
        q[who]++;
    }
    
    /* 前回相手が裏切った場合 */
    if ( opposite[ round - 1 ] == Defect ) {
        count_d[who]++; /* 裏切りの数をカウント */

        if ( flag[who] > 0 ) {
            flag[who] = 0; /* 相手を見誤ったときはフラグを戻す。*/
            talk(who, "ん?違ったか?" );
        }
    }


142 :137 = DW+:02/04/22 08:29

    /* 10ターン戦ったら非協調系キャラクターの分析をする */
    if ( round == FIRST_ROUND + 10 ) {
        if ( ( count_d[who] == 1 ) && ( opposite[ FIRST_ROUND ] == Defect ) ) {
            flag[who] = 0x11; /* アスカ様に予約したフラグ値 */
            flag[who] = -1; /* シンクロ率ダウン攻撃 */
            poo[who] = 0;     /* 女の子に最後っぺは無し */
            talk( who, "♯♯♯ アスカのシンクロ率、急速に低下していきます! ♯♯♯" );
        } else if ( count_d[who] >= 10 ) {
            flag[who] = -1;
            talk( who, "人間不信裏切り君 ハケン!( ̄ー+ ̄)キラーン" );
        } else if ( ( count_d[who] >= 9 ) && ( opposite[ round - 1 ] == Cooperate ) ) {
            flag[who] = 1;
            talk( who, "ヒッキー君━━━━━━( °∀ °)━━━━━━キター!!!!");
        }
    }

    /* 最後っぺ野郎くん対策 といいつつ他の囚人にも最後っぺ */
    if ( ( round == ROUND + FIRST_ROUND - 1 ) && ( poo[who] != 0 ) ){
        switch ( rand() % 3 ) {
            case 0: talk( who, "オナラ Pu〜♪ " ); break;
            case 1: talk( who, "勝負!" ); break;
            default: talk( who, "最後もらい!" );
        }
        return Defect;
    }

    /* 態度決定者への反応 */
    if ( flag[who] < 0 ) return Defect; /* 人間不信裏切り君ほか */
    if ( flag[who] > 0 ) return Cooperate; /* ヒッキー君ほか */

    /* 裏切る相手との協調を模索 10ターン目 ヒッキー君対策 */
    if ( ( round == FIRST_ROUND + 9 ) && ( count_d[who] >= 9 ) ) return Cooperate;


    /* それ以外判定部 */
    if ( p[who] == q[who] ) /* 鈍感な相手には裏切り */
        return Defect;
    else if ( p[who] > q[who] ) /* 敏感な相手とは協調 */
        return Cooperate;
    else
        return ( (round % 2 ) == 0)? Defect : Cooperate; /* 交互に手を変えて様子を探る */

}

143 :デフォルトの名無しさん:02/04/22 13:30
http://page.auctions.yahoo.co.jp/jp/auction/44457554

144 :DW+:02/04/22 17:58
>>133
総合得点ではなくて勝点制なら確率で次のラウンドがあるか決めるのも
ありだと思う。

ラウンド数の最大限を知りたいのは、相手によらず出す手が決まっているような
戦略を手間をかけずに作れるメリットがあるので。

145 :DW+:02/04/22 18:12
どの相手にも同じ乱数で相手する乱数表戦略を作ってみた。

#define SIZE_OF_RND_TABLE (ROUND * 4) /* 余分に作って実際に使う部分の平均値を変動させる */

int _random_table(int round) /* 乱数表 */
{
/* 自分を含めどの相手にも同じパターンの乱数を返す */
/* 自分と対戦するときの得点は平均2.25点から平均2点に下がる */

static int table_maked = 0;
static int rnd_table[ SIZE_OF_RND_TABLE - 1 ];

/* 乱数表初期化 1回だけ実行 */
if (table_maked++ == 0 ) {
int i, tmp, r;

/* 0,1 を交互に入れておく 全体の平均値は0.5になる */

for (i = 0; i < SIZE_OF_RND_TABLE; i++ )
rnd_table[ i ] = i % 2;

/* シャッフル */
for( i= 0; i < ROUND; i++ ) {
tmp = rnd_table[ i ];
rnd_table[ i ] = rnd_table[ r = rand() % SIZE_OF_RND_TABLE ];
rnd_table[ r ] = tmp;

/* まだ乱数に癖があるようなら下を追加する */
/* rand(); rand(); */
}
}

return rnd_table[ round ];
}

146 :DW+:02/04/22 18:17
>>145 ミスばっかりしてるけどmaked は madeの間違いね。馬鹿丸出し。

147 :デフォルトの名無しさん:02/04/22 18:49
おまたせしました。第3回囚人のジレンマ大会を開催いたしました。
今回のエントリーは、

0. 最強しっぺ返し君
1. 人間不信裏切り君
2. ゴルゴ13
3. hoge
4. DOWNING 改変版 DW+
5. DW+2
6. lastpoo
7. ヒッキー君
8. 偽善君
9. アスカ
10. 全痴全脳の神
11. 普通の人?

でした。大会ソースは、

http://www.geocities.co.jp//SilkRoad-Ocean/5567/prisoner3.c.txt

で、結果です。


[ 1 ] オナラ Pu〜♪
[ 1 ] 人間不信裏切り君 ハケン!( ̄ー+ ̄)キラーン
[ 1 ] オナラ Pu〜♪
[ 1 ] 勝負!
[ 1 ] 勝負!
[ 1 ] 勝負!
[ 0 ] オナラ Pu〜♪
[ 1 ] 最後もらい!
[ 0 ] オナラ Pu〜♪
[ 0 ] ヒッキー君━━━━━━( °∀ °)━━━━━━キター!!!!
[ 0 ] 最後もらい!
[ 0 ] 勝負!
[ 0 ] ♯♯♯ アスカのシンクロ率、急速に低下していきます! ♯♯♯
[ 0 ] 最後もらい!
[ 0 ] 最後もらい!
0 1 2 3 4 5 6 7 8 9 10 11 sum
0 3000 999 3000 2667 3000 2997 2997 1300 2997 2058 2498 3000 30513
1 1004 1000 1004 5000 1020 1024 3996 1400 4996 4988 3000 3000 31432
2 3000 999 3000 4993 3000 2997 2997 1399 2997 4995 2997 3000 36374
3 2667 0 8 1002 8 8 3496 795 3996 3995 2250 8 18233
4 3000 995 3000 4993 3000 2997 2997 1395 2997 4993 2997 3000 36364
5 3002 994 3002 4993 3002 2998 2998 2979 2998 4993 2997 3002 37958
6 3002 251 3002 1716 3002 2998 2998 1155 2998 3009 1626 3002 28759
7 1300 900 904 4305 920 2999 3670 2982 3015 3014 2900 2997 29906
8 3002 1 3002 1501 3002 2998 2998 2975 2998 2999 1501 3002 29979
9 2063 3 5 1505 8 8 2984 2974 2999 3000 1500 3000 20049
10 2503 500 507 2250 507 507 3496 900 3996 4000 2000 2250 23416
11 3000 500 3000 4993 3000 2997 2997 2957 2997 3000 2250 3000 34691


148 :デフォルトの名無しさん:02/04/22 18:53
優勝 DW+2
2位 ゴルゴ13
3位 DOWNING 改変版 DW+

でした。

149 :DW+:02/04/22 18:59
>>147 第3回大会ご苦労さま。

>>98 で 乱数の初期化を入れろって書いたけどしてありますね。
大変失礼しました。


勘違いで書いているところ他にもあるなぁきっと。


今朝、教育テレビのイタリア語会話を見てたら

Sbagliando s'impara. - 人は間違えながら学ぶ(失敗は成功のもと)

っていってたけど、自分の場合ぜんぜん学んでないな。

150 :DW+:02/04/22 19:04
>>147
ひとりだけはしゃいでいるみたいで恥ずかしい。 > DW+2

なので次回大会は他にしゃべる人がいないければ
talk()は無効化してください。

151 :デフォルトの名無しさん:02/04/22 19:20
あ、これはお願いなんですけど、できればプリプロセッサは
使わない方向で。と。なるべく囚人関数の中で自己完結していただけると、
楽です。僕が。

152 :デフォルトの名無しさん:02/04/22 19:24
もうしわけありません。3回目のソースは下でした。番号合ってないと解りづらい。。。
http://www.geocities.co.jp//SilkRoad-Ocean/5567/prisoner4.c.txt


153 :デフォルトの名無しさん:02/04/22 20:47
Prisonerクラスを作ってやりませんか?
class Prisoner{
virtual int decide()=0;
virtual void notify(int result)=0;
}
------------------------------------
while(1){
a=prisoner_a->decide();
b=prisoner_b->decide();
prisoner_a->notify(b);
prisoner_b->notify(a);
if ( ( a == 0 ) && ( b ==0 ) ) { pa+=3;pb+=3; } /* 協調:協調 */
if ( ( a == 1 ) && ( b ==0 ) ) { pa+=5;pb+=0; } /* 裏切り:協調 */
if ( ( a == 0 ) && ( b ==1 ) ) { pa+=0;pb+=5; } /* 協調:裏切り */
if ( ( a == 1 ) && ( b ==1 ) ) { pa+=1;pb+=1; } /* 裏切り:裏切り */
}

こんな感じで・・・


154 :デフォルトの名無しさん:02/04/22 22:28
>>153
“大会”自体が何回か繰り返される場合,大会の成績によって
個体数を増減するのが簡単になるっすね。
より本格的になってきた感じ。

ってことで,しっぺ返しクラス。

class TitForTat: public Prisoner {
    int _hand;
public:
    TitForTat(){ _hand = Cooperate; } // 初期は協力
    int decide() { return _hand; }
    void notify(int result){ _hand = result; } // 相手の真似をする
};

155 :デフォルトの名無しさん:02/04/22 22:41
あと,ゴルゴ13クラス。

class Golgo13 : public Prisoner {
    int _hand;
public:
    Golgo13(){ _hand = Cooerate; } // 初期は協力
    int decide(){ return _hand; }
    void notify(int result) {
        if (result == Defect) _hand = Defect;
    } // 一度でも裏切られると,もう協力しない
};

156 :デフォルトの名無しさん:02/04/23 00:47
>>153
自分の名前も持てると結果の表示が楽だね。

157 :デフォルトの名無しさん:02/04/23 01:19
良スレ上げ。

158 :デフォルトの名無しさん:02/04/23 01:32
>>1はC++のコンパイル環境あるの?

159 :デフォルトの名無しさん:02/04/23 01:49
>>158 環境あるざんす。というか gcc なので。

基本的に anti-OO なのでクラスは読めても設計できないし、
別にクラスでやる意味なさそうに思うけど、
勉強のためにいいかなあ、とあたし個人は思うのですけど、

どうでしょう?

160 :デフォルトの名無しさん:02/04/23 03:58
>>159
オーバーライドで共通インタフェイスがつかえたりするんで
いいかなとも思ったが、C++でやる意味もあまり無いかなとも思った。

161 :153:02/04/23 08:24
>C++でやる意味もあまり無いかなとも思った。
名前が衝突する可能性がほぼ0になりますよ。

class Prisoner{
virtual int decide()=0;
virtual void notify(int result)=0;
virtual char* getName()=0;
}

こんな感じですかね?

162 :デフォルトの名無しさん:02/04/23 20:24
>>100 バグはけーん!
- #define DEF(x) int x (int round, const char* own, const char* opposite, int who )
+ #define DEF(x) int x (int round, int* own, int* opposite, int who )

そのまま取り込んでもらえるとは思ってなかったので、放置しちゃってました。スマソ…

ROUND定数に関しては、お騒がせしてしまったようですが、
例えばこんな囚人はどうでしょう。

int halfandhalf( int round, int*, int*, int who ) /* 弐重人格者 */
{
static int flag = 0;
if ( who == 3 ) {
flag = flag >= 2 ? 1: flag +1;
return 0;
}
if ( flag == 2 ) { return who; }
if ( round == 0 ) { flag = 0; }
return ( round <= ROUND/2 ) ? Cooperate: Defect;
}


163 :デフォルトの名無しさん:02/04/23 23:00
自分が無数の最適化オプションを使いこなせないからといって幼稚園児並と表現するのはどうかと。

164 :デフォルトの名無しさん:02/04/23 23:37
良スレ上げ
>>163誤爆?

165 :デフォルトの名無しさん:02/04/23 23:49
ここらでもう一度、誰か囚人の関数規定とサービスファンクション(?)を詳しく書いてくれ!

166 :デフォルトの名無しさん:02/04/24 00:30
こんな感じでいい?

>>囚人関数
int func_name(int round, int *own, int *opposite, int who);
int round:現在のラウンド数
int *own:これまでの自分の手
int *opposite:これまでの相手の手
int who:個人ID(?)
返り値:0=協調,1=裏切り(※必須)

>>サービスファンクション
void talk( int who, char *mes );   // 自分のキャラに発言させる
int who:個人ID
char *mes:発言内容
返り値:無し

int _random_table(int round);     // 乱数取得
int round:ラウンド数
返り値:乱数

167 :デフォルトの名無しさん:02/04/24 00:35
enum Attitude {協調:裏切り};
Attitude func_name(int round, int *own, int *opposite, int who);
してくれ。見にくい。

168 :デフォルトの名無しさん:02/04/24 06:00
囚人を特定して対応する戦略が強いみたいですね。
なんかこう、意外な戦略が強い、みたいなのはでてこないでしょうか。

169 :赤木先生:02/04/24 08:00
ジレンマ・・・作った人間の性格が伺えるわね。

170 :デフォルトの名無しさん:02/04/24 08:04
くそー一般命令と特殊命令ってなんだよヽ(`Д´)ノ
おじさん怒っちゃうぞ!!

171 :デフォルトの名無しさん:02/04/24 08:06
ニューラルネットワークな囚人ってどうなんだろ

172 :デフォルトの名無しさん:02/04/24 09:21
>>166
それじゃあ、すごくわかりずらいと思うな。
やっぱC++でちゃんとやろうよ

talkは_talkとかにして
talkで使いたい人が、ヘッダで読み込めばOK
ヘッダにわけわからないdefineとか使うのはダメ
まあ、理想はSystemクラスだけど。
プリプロセッサを使うのはあまりよくないという事なので。

ところで、乱数なんてのは独自に作ればいいと思うのですが・・・
多数公開されてますし


173 :デフォルトの名無しさん:02/04/24 12:48
>>172 プログラム書いて示してくれたまへ。君が。
っていうか、>>145 の意味も解らずに何を言っとるか。

174 :デフォルトの名無しさん:02/04/24 18:57
>>172
166の乱数は本来は囚人なんだけど乱数(0,1)取得としても使えるので
サービスファンクションとして取り上げたんじゃないかな

1の使ってる処理系だと乱数がうまく機能しないらしい

175 :デフォルトの名無しさん:02/04/24 23:32
量すれ上げ。
(´-`).。oO(なんでこんなにさがってるんだろ。。。)

176 :デフォルトの名無しさん:02/04/24 23:43
>>111 どっちにしてもメインメモリにリニアには展開出来なんだから


177 :デフォルトの名無しさん:02/04/24 23:43
>>175
いいスレだが閉鎖的。


178 :デフォルトの名無しさん:02/04/24 23:45
>>177
閉鎖的かな。。。。
確かにほぼCオンリーなんでC知らない人は参加しずらいだろうけど。。。

179 :デフォルトの名無しさん:02/04/24 23:53
>>178
初めの方読めばわかるけど平気で人追い出してみたりとかね。
ネタはいいが性格は悪い。

180 :デフォルトの名無しさん:02/04/24 23:53
>>8
あははは、爆笑
いえてる

181 :デフォルトの名無しさん:02/04/24 23:55
ぬぅんちゃきん

182 :デフォルトの名無しさん:02/04/25 00:00
MAGIシステム作ってます。乞うご期待。
#もちろんバルタザールは裏切ります。最後に。

int magi( int round, int *own, int *opposite, int who )
{
int foo;

foo =
casper( int round, int *own, int *opposite, int who ) +
melchior( int round, int *own, int *opposite, int who ) +
balthasar( int round, int *own, int *opposite, int who );

if ( foo > 1 ) return 1; else return 0;
}

int casper( int round, int *own, int *opposite, int who ) /* 科学者としての私 */
{
}

int melchior( int round, int *own, int *opposite, int who ) /* 母親としての私 */
{
}

int balthasar( int round, int *own, int *opposite, int who ) /* 女としての私 */
{
}


183 :デフォルトの名無しさん:02/04/25 00:15
>182
MAGIは多数決システムと聞くが。

184 :デフォルトの名無しさん:02/04/25 00:20
自立自爆プログラムが可決されますた。。

185 :デフォルトの名無しさん:02/04/25 00:53
>>183 そうなってるYO!

「総理!こんな簡単なソースも読めない若者がム板に増えています!
円周率を3として教えたゆとり教育の弊害ではないでしょうか!総理!」

186 :デフォルトの名無しさん:02/04/25 00:58
>>182
> if( foo > 1 )

っての

if ( foo >= 2 )

のがよかったかもな。可読性では。

187 :デフォルトの名無しさん:02/04/25 07:35
>>174 いえ、ふつーに機能します。

ふつーに使うと乱数なので毎回結果が違うので、
大会自体を1000回位まわして平均をとらなきゃな、
と悶々としていたところです。

次回の大会から「でたらめ君」を復活させます。
DW+さんありがとう。

188 :デフォルトの名無しさん:02/04/25 07:39
MAGIには誰の脳みそを入れるのですか?

189 :172=154:02/04/25 08:55
は?
プログラムって何のプログラムですか?
乱数生成のですか?

>どの相手にも同じ乱数で相手する乱数表戦略を作ってみた。
線形合同法はシードが同じなら、いつでも同じなんですよね・・・
stdlibの乱数は線形合同法ですね。

で、145の意味はわかってますが何か?
しかも、数学的に何の意味もない事もわかってますが何か?
整数から、{0,1}への写像を定義して、
整数側からランダムに要素を選ぶ事にどんな意味があるのか教えていただければ
幸いです。

排他的というより、知らないものは見ないって感じですか?

統計データをファイルから読み込ませたプログラムを作ろうと思った
のですが、C++でクラス化しないということなので、
もうやめます。

190 :デフォルトの名無しさん:02/04/25 08:56
>>189
頭よくて?も性格悪いと人間的にダメ。

191 :デフォルトの名無しさん:02/04/25 09:24
>>189 >>145 は乱数の生成に意味があるのではなく、
テーブルを作って誰もが同じ乱数列を使うことに意味があるんだYO!
君超勘違い君。

君もC++使えないからって。子供みたいだね。君に誰も頼んでもいないしね。

192 :189:02/04/25 20:32
>テーブルを作って誰もが同じ乱数列を使うことに意味があるんだYO!
だから、シードが同じなら、同じ乱数列だって言ってんだろ。

>君もC++使えないからって。子供みたいだね。君に誰も頼んでもいないしね。
捨て台詞はくなよ、見苦しい。
まあ、C++使えないからじゃなくて、
向上心が無いから、つまんねって感じ。
Cでやるにも、もっと良いコーディング方法あると思うけど・・・

ちなみに、みなさん文系の人だと思うので、
理系なら誰でもわかるような事だとは思いますが、書いておきますと(既出かも?)
皆さんが作ってる囚人には2パターンあります。
一つは初めから手が決まっているもの。
二つ目は、相手の手に応じて手が決まるものです。

ランダムに協力と裏切りを選択するものも一つ目に含まれます。
ただ、ランダムなものは少し特殊で、どのような戦略をとっても、
勝ち負けの確立は5分5分になります。(確立分布による、と書く方が適切かも)
要するにランダムなものに対して戦略を立てても無駄なわけです。
じゃんけんに戦略なんて物が存在しないのと同じ事です。

すべての囚人が1つ目のパターン、すなわち最初から手が決まっている場合、
そのパターンが何かわかっていれば、それらのどの囚人よりも強い囚人は
計算で容易に求める事が出来ます。
そういうわけで、手の内を公開しつつこのゲームをする場合、
パターン1に当てはまる囚人は作ってもほとんど意味はありません。

おもしろいのは二つ目ですね。
そして二つ目のパターンに属する囚人の特徴を検証するために
パターン1を使うのは無難な方法ですね。
ただ、こっちも結局は・・・それほど意味を持たないんですね。
一回事の意思決定が完全に独立なため、結局は期待値に即した値しか
得られないのです。
要するに統計より確率分布を計算して、手を決める囚人が平均的に強い、という事は
計算から簡単にもとまってしまうんですね。

ゲーム理論(ドラマとかも)について思う事は、
あまりにもモデルが単純すぎて、解析結果として何も得られない
悲しい学問だなー、と。
反論があればどうぞ。当方、ゲーム理論の専門家じゃないので
専門用語はなるべく避ける方向でよろしく。

193 :デフォルトの名無しさん:02/04/25 20:36
MAGI カスパーのアルゴリズムがいまいちかも。

int magi( int round, int *own, int *opposite, int who )
{
int m = 0, b = 0, c = 0;
char opinion[ 2 ][ 6 ] = { "賛成", "否認" };

m = melchior( round, own, opposite, who );
b = balthasar( round, own, opposite, who );
c = casper( round, own, opposite, who );

/* printf( "MELCHIOR1 %s: BALTHASAR2 %s: CASPER3 %s\n", &opinion[ m ], &opinion[ b ], &opinion[ c ] ); */

if ( ( m + b + c ) > 1 ) return 1; else return 0;
}


194 :デフォルトの名無しさん:02/04/25 20:36

int melchior( int round, int *own, int *opposite, int who ) /* 科学者としての私 */
{
/* 定量的に判断 */

static int c[ 2 ] = { 0, 0 }, d[ 2 ] = { 0, 0 };

if ( who == 3 ) {
c[ 0 ] = 0;
c[ 1 ] = 0;
d[ 0 ] = 0;
d[ 1 ] = 0;
return 0;
}

if ( round == 0 ) return 0;

if ( opposite[ round - 1 ] == 0 ) c[ who ] ++; else d[ who ] ++;

if ( c[ who ] >= d[ who ] ) return 0; else return 0;
}

int balthasar( int round, int *own, int *opposite, int who ) /* 母親としての私 */
{
/* 現実的に判断 */

if ( round == 0 ) return 0;

if ( ( opposite[ round - 1 ] == 0 ) && ( own[ round - 1 ] == 0 ) ) return 0; else return 1;
}

int casper( int round, int *own, int *opposite, int who ) /* 女としての私 */
{
/* 秋の空 */

if ( round == 0 ) return 0;
if ( round == 1 ) return 1;
if ( round == 999 ) return 1;

if ( opposite[ round - 1 ] == 1 )
if ( opposite[ round - 2 ] == 1 )
return 0; else return 1;

return 0;
}


195 :デフォルトの名無しさん:02/04/25 22:07
melchior の条件判断間違い。

- if ( c[ who ] >= d[ who ] ) return 0; else return 0;
+ if ( c[ who ] >= d[ who ] ) return 0; else return 1;

そこそこは行くけどトップにはなれない。というか DWシリーズ強すぎ。
やはり個別対応をするべきか?

196 :DW+:02/04/26 00:00
いろいろ誤解や荒れる原因を作ってしまい、申し訳ありません。

>>145 は囚人で、基本的に自分や他の人が作った囚人の評価用です。
>>94 あたりで、でたらめ君が欠場になったのと、>>144 の関連で
あらかじめ出す手を決めてしまう戦略の例を出したかったので発表
しました。

こちらの手が丸見えですから、サービスファンクションになったのは
びっくりしました。

でも、要は使い方次第だし、丸見えであるのを利用する囚人が出て
くればここで議論になると思ったので、その時は指摘しなかったのです。


私の発言の至らなさから皆さんに不快な思いをさせてしまったことを
お詫びします。

197 :デフォルトの名無しさん:02/04/26 00:47
んじゃ、くだらん煽り・議論はココまで。
参加したいヤシは参加して、したくないヤシは参加しなければよい。
とりあえず言語はCで、その他言語、C++(クラス化)等でいい案があるならまずソースを出せと。
で、皆がそっちのいいと思うなら自然にそっちに逝くだろうと。

■囚人のジレンマについての説明は、>>42
■関数形式については、>>166 (乱数導入については1に任せる)

っていうか、1はまだいるのか?(ワラ

■エントリー囚人 =======================================

最強しっぺ返し君 >>49
人間不信裏切り君 >>49
ゴルゴ13 >>77
hoge >>49
random >>49
ヒッキー君 >>87
偽善君 >>111
アスカ >>113
全痴全脳の神 >>114
普通の人? >>124
DW+2 >>141-142
MAGI >>193-195

198 :デフォルトの名無しさん:02/04/26 03:29
>>197 いますよー
ポリシー的にコテハン使ってないけど、
MAGI書いたのは1ですよー。アスカも。

で、ここら辺で考察なんですけど、強い囚人は確実に
3000近くと5000近くをとってますね。まあそうなんですけど。
もうちょっとばらけないかなあ、と思ってみたり。

というかTfT別に強くないじゃん。

199 :デフォルトの名無しさん:02/04/26 06:53
結局>>1がエヴァ好きなのはようわかった。
俺も好きだ

200 :デフォルトの名無しさん:02/04/26 07:42
>>197
>>42の一行目でいきなり煽られて不快。

201 :デフォルトの名無しさん:02/04/27 01:26
>>200
ワラ。それは無視しる!

202 :デフォルトの名無しさん:02/04/27 01:58
まだやってるのか知らないけど。。。。

// われは全痴全脳の神
int yhwh(int round, int *own, int *opposite, int who){

  int  i,a=0,b=0;

  for (i=0;i<round-1;i++){
    if (*opposite == 1){ a++; }
    else{ b++; }
    oppositte++;
  }

  if (a>b){
    _talk(who,"神の裁き!!");
    return 1;
  }
  else{
    _talk(who,"汝に祝福あれ!");
    return 0;
  }
}



203 :デフォルトの名無しさん:02/04/27 02:24
ヤハウェ

204 :デフォルトの名無しさん:02/04/27 04:08
おまえら確立の勉強しれ
独立事象に対してなぜに解析を?と問い詰めていいでしょうか?

205 :デフォルトの名無しさん:02/04/27 04:31
>>204 おまえは漢字の勉強をしろ。
乱数を使ってる囚人はでたらめ君だけだ。

206 :デフォルトの名無しさん:02/04/27 06:12





























207 :デフォルトの名無しさん:02/04/27 07:58
上げ〜♪

おまけ

int devil (int round, int *own, int *opposite, int who ) {
  static int me = 0, ent = sizeof ( results ) / sizeof ( results [0] ) ;
  int i, j ;
  if ( who == 3 ) {
    if ( --ent == 0 ) {
      ent = sizeof ( results ) / sizeof ( results [0] ) ;
      while ( prisoners [ me ] != devil ) me++ ;
      for ( i = 0 ; i < ent ; i++ ) {
        for ( j = 0 ; j < ent ; j++ ) {
          results [i][j] = ROUND ; } }
      for ( i = 0 ; i < ent ; i++ ) {
        results [i][me] = 0 ;
        results [me][i] = ROUND * 5 ; } } }
  return 1 ; }

208 :デフォルトの名無しさん:02/04/27 12:25
>>377
いいじゃんC++Builder5用だって。俺も何冊か持ってるが、そのままほとんど
使えるよ。CLXについてはさすがに載ってないけどね。

209 :デフォルトの名無しさん:02/04/27 23:06
アゲマス

210 :デフォルトの名無しさん:02/04/27 23:06
void main()
{
vector<Lengthen *> show_order;
// 好きな順に登録
show_order.push_back(new Name("(´д`;;)"));
show_order.push_back(new Age(14));
show_order.push_back(new Gendor(Gendor::Male));
show_order.push_back(new End);
// ヘッダ
for_each(show_order.begin(), show_order.end(), bind2nd(mem_fun1(&Lengthen::puttitle), &cout));
// データ
for_each(show_order.begin(), show_order.end(), bind2nd(mem_fun1(&Lengthen::putdata), &cout));
}

残りは推測しる

211 :デフォルトの名無しさん:02/04/27 23:56
int hypnotist ( int round, int *own, int *opposite, int who ) {
  if ( round != 0 ) {
    own [round - 1] = Cooperate ;
  }
  if ( round > 1 ) {
    own [round - 2] = Defect ;
  }
  return Defect ;
}

212 :デフォルトの名無しさん:02/04/28 12:29
新入りです。
よろしくお願いします。

int newbee(int round, int *own, int *opposite, int who){

int i;
double reliability;

for(i=0,reliability=0;i<round;i++){
if(opposite[i]==Cooperate)reliability+=power(3,i);
else reliability-=power(3,i);
}

if(reliability>0)Defect;
else Cooperate;

}


int oldbee(int round, int *own, int *opposite, int who){

int i;
double reliability;

for(i=0,reliability=0;i<round;i++){
if(opposite[i]==Cooperate)reliability+=power(3,i);
else reliability-=power(3,i);
}

if(reliability>0)Cooperate;
else Defect;

}

whoは何に使うのですか?

213 :デフォルトの名無しさん:02/04/28 12:57
type
 TForm1 = class(TForm)
  Memo1: TMemo;
  Button1: TButton;
  procedure Button1Click(Sender: TObject);
  function calc : String ;
 private
  { Private 宣言 }
 public
  { Public 宣言 }
  i , j : integer ;
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

function calc : String ;
begin
  result := IntToStr(i + j);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  i := 1 ;
  j := 2 ;

  Memo1.Lines.Add(calc);
end;

end.


214 : :02/04/28 16:41
void the_end(void) /* 終了君 */
{
exit(1);
}


215 :デフォルトの名無しさん:02/04/28 18:38
昔bitでやってたね。出題は竹内先生だったとおもう。

216 :デフォルトの名無しさん:02/04/29 11:17
189に蹴散らされて終了した?

217 :デフォルトの名無しさん:02/04/29 11:20
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;

if (!m_wndToolBar.CreateEx(this, TBSTYLE_ALTDRAG , WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // 作成に失敗
}
//ここから追加
TBBUTTON button[5];
for(int i = 0 ; i < 5 ; i++){
button[i].fsState = TBSTATE_ENABLED;
button[i].fsStyle = TBSTYLE_CHECKGROUP;
button[i].iBitmap = 0;
button[i].idCommand = m_wndToolBar.GetItemID(10);
button[i].iString = 0;
}
CToolBarCtrl &ToolBarCtrl = m_wndToolBar.GetToolBarCtrl();
ToolBarCtrl.AddButtons(5,button);
//ここまで

218 :デフォルトの名無しさん:02/04/29 12:43
ネットワーク対戦にしてよ

219 :デフォルトの名無しさん:02/04/29 14:47
>>216
俺が見る限りでは、>>189 の方が蹴散らされて
今頃は枕を涙で濡らしていると思われ。
つーか、お前 >>189 だろ。(w

グダグダ言う前に強いアルゴリズムをうpしれ。
そうすれば皆、話を聞いてくれるぞ。

220 :デフォルトの名無しさん:02/04/29 19:01
>>218
同意、Socketでお互い接続して戦えるみたいな。

221 :デフォルトの名無しさん:02/04/29 23:23
>>1 です。旅行に行ってました。
Unix用でよければネットワーク対戦用のプログラム書きます。が。
あ、こっちでサーバ作って立てればいいのですね。

222 :デフォルトの名無しさん:02/04/29 23:57
>>221
それかアプロダ作って好きな相手といつでも戦える方が便利かも。
gcc使える人限定になりそうだけど。

223 :デフォルトの名無しさん:02/05/01 04:22
age

224 :デフォルトの名無しさん:02/05/02 00:19
ryousureage

225 :デフォルトの名無しさん:02/05/02 06:35
>>1 です。あんまり興味がなくなってきてしまいました。
すんまへん。どなたか引継ぎを。

226 :デフォルトの名無しさん:02/05/02 08:59
>>225
こんなスレ潰してしまえ。

227 :デフォルトの名無しさん:02/05/04 01:47
それでもあげる

228 :デフォルトの名無しさん:02/05/04 01:55
class Shujin
{
private:
    char result[1000];
public:
    char Decide(void);
  char GetResult(int);
};


229 :デフォルトの名無しさん:02/05/04 01:57
Shujin::Decide()
{
   return rand()%2;
}

Shujin::GetResult(int n)
{
   return result[n];
}

230 :デフォルトの名無しさん:02/05/04 02:02
//used for the return value of Shujin::Decide
enum {RSLT_CONFESS, RSLT_BETRAY};

231 :デフォルトの名無しさん:02/05/08 22:51
>>228-230
で、何なの?(w

232 :デフォルトの名無しさん:02/05/13 19:07
あれ、このスレ終了?

>Unix用でよければネットワーク対戦用のプログラム書きます。が。
この人には無理だよ。

やっぱ、文系ってアホだな・・・


233 :デフォルトの名無しさん:02/05/13 19:13
>>232
死んだスレageるあなたの方がアホです。
VBスレはもう飽きたのかい?

234 :デフォルトの名無しさん:02/05/13 19:25
>>233
誤爆?
全部Cだぞ

235 :デフォルトの名無しさん:02/05/13 21:07
int hypnotist ( int round, int *own, int *opposite, int who ) {
  if ( round != 0 ) {
    own [round - 1] = Cooperate ;
  }
  if ( round > 1 ) {
    own [round - 2] = Defect ;
  }
  return Defect ;
}

236 :デフォルトの名無しさん:02/05/26 07:39
sage

237 :デフォルトの名無しさん:02/06/05 15:36
age

238 :デフォルトの名無しさん:02/06/05 21:28
http://darwin.esys.tsukuba.ac.jp/IPD/report.html
コンテストは既にあった。
発展性がない事に誰もが気づいたので、もうやってない。

TFT(しっぺ返し)をあたかも自分が作ったように載せてるバカは
どこのバカだ?

239 :デフォルトの名無しさん:02/06/05 21:57
1は恥ずかしくて逃亡しました

240 ::02/06/05 23:37
新しい人工知能試行ゲーム考えたんだけど、実装がなかなかうまくいかん。。
もうすぐできる。

241 :デフォルトの名無しさん:02/06/06 00:08
>>240
ゲームの仕様を書いてくれ。
囚人のジレンマ並にクソだったら、殺すけど。

242 :1:02/06/06 03:00
1です。お久しぶり。最初は面白いかと思ってスレ立てたんだけど、
それ自体は面白かったんだけど、囚人のジレンマが面白くなかった。
自由度が2しかないものね。協調か裏切りかの。
なんかモデル化して面白いものあるかなあ。株とか?

243 :たれ:02/06/06 23:20
ども。awkで囚人のジレンマやってて、思考アルゴリズムがなんか無いかと思って
ぐぐるでこのスレ発見しました。

こっちでも9つほどのプログラムを対戦させてみましたが、やっぱしゴルゴ13
(当方では「謝罪と賠償を求めるニダくん」と呼んでいるが)はわりと強いみた
いです。


244 :デフォルトの名無しさん:02/06/06 23:21
なぜ awk で?

245 :たれ:02/06/06 23:22
楽だから。

246 :デフォルトの名無しさん:02/06/06 23:26
awkは書かねぇ

247 :たれ:02/06/07 00:04
たった一行

248 ::02/06/07 00:09
>>241
tera風のゲーム。主人公はアメーバ。
n×mの升目をつくり、その中で、
・上下左右どこかに移動する
・自分以外との接触が起きたら、戦うか回避するかを決める
・ある条件下で細胞分裂可能

みたいなかんじ。できればWinのDLL使って、自由にAIを参加・削除
できるようにしたい。

249 :デフォルトの名無しさん:02/06/07 00:24
>>248
あー、俺も作った事ある。
AI側のインターフェースを相当上手く作らないと、
AI側の実装がきつい。
テラリウムのやり方は、俺のよりは優れてるな。
でも、やっぱり醜い。

で、AI側の実装がきつかったから、3種類くらい作ってすぐ止めてしまった。
まあ、動かすと面白い事は確か。

環境の実装のコツは、がちがちのOOで作る事。
OOできる人間以外は、たぶん複雑すぎて作れないと思う。
嘘だと思った人は、挑戦してみるといい。
それと、テラでいうscanに相当するものは、
おそらく全検索する以外に方法はない。
そして、これが生物の数の上限を決めてしまう。
生物のデータを参照する場合は、コピーを参照させなきゃいけなかったりするし、
生物間の通信を断つために、リフレクションでstaticメソッドの有無を調べなきゃいけなかったり
すごく大変だけど、OOできれいに記述できるので気分はいい。

http://pc.2ch.net/test/read.cgi/tech/1022502611/l50
こんなのもある

250 ::02/06/07 00:39
>>249
とりあえずいけるとこまでCでがんばってるけど、、、
やっぱデータ隠蔽とかに限界がある。。
OOにすると初心者が近寄れなくなる。。

251 :デフォルトの名無しさん:02/06/07 00:47
DLL実装ってのには賛成。
VBなんかでもDLL作れるんだろ?そういう意味では門戸が広くなるし。
あとは面白そうなゲームシステムに期待。囚人のジレンマの時は
参加してなかったので面白そうになれば参加したいぞ。

252 :デフォルトの名無しさん:02/06/07 00:54
>OOにすると初心者が近寄れなくなる。。
んなこたーない
テラリウムは簡単だろ?
OOは使う側は初心者でいいんだが、
作る側は上級者である必要がある。

そもそも初心者に参加してもらうって姿勢は間違ってると思うぞ。

http://pc.2ch.net/test/read.cgi/tech/1022502611/l50
これなんて、まともにできる奴は日本に300人くらいしかいないだろう。
もちろん俺は手も足も出ない。

253 :デフォルトの名無しさん:02/06/07 23:26
>>252
もうちょっと低レベルな初心者にも参加できたらな。。。と考えている。
で、独自形式のスクリプトにしてしまえばGUIでスクリプト作成するものとか
も作れるんで、PCをゲームにしか使ってないようなユーザにも手を出せるかな
と思ったんだが、パーサとか余分なもんを実装しないといかん。。。

いい方法ないかな。。。

254 :たれ:02/06/07 23:35
なんかむかし、BASICでロボットのプログラムを組むゲームがあったような


255 :www:02/06/14 19:34
int testkun(int round, int *own, int *opposite, int who){
/*てすとくん*/
if(round<4)return 0;
if(opposite[round-1]=1 || (opposite[round-2]=1 && opposite[round-3]){
  return 1;
else
  return 0;
}
}


256 :www:02/06/14 19:34
age

257 :www:02/06/14 19:35
あ、↑何気に256ゲットしてた(w

258 :デフォルトの名無しさん:02/06/14 19:46
>>255-257
もう終わったけど、なんか用?

259 :デフォルトの名無しさん:02/06/15 11:00
>>253
思いつきだけど表計算みたいなのはどう?
一列×回数行にする。
記述だけならテキスト・エディタでもできるし、
関数の実装は追々やっていけばいい。

260 :デフォルトの名無しさん:02/06/16 18:47
あげ

261 :デフォルトの名無しさん:02/06/16 23:45
>>259
いまいち意味不明。
詳解キボンヌ

262 :デフォルトの名無しさん:02/06/19 01:03
age

263 :70:02/06/19 13:24
perl or rubyのスクリプト書かせてCGIでアップロードさせて対戦するとか。
思いっきり記述を簡略化させれば簡単に覚えらるかも。

>>70みたいにif文省略するとかなりすっきりするよ。

264 :デフォルトの名無しさん:02/06/23 20:23
255かっこがひとつないw

265 :デフォルトの名無しさん:02/07/06 14:09
age

266 :デフォルトの名無しさん:02/07/07 12:38
揚げ

267 :デフォルトの名無しさん:02/07/10 20:00
菱擂れ安芸

268 :デフォルトの名無しさん:02/07/16 18:19
あげてみる

100 KB
■ このスレッドは過去ログ倉庫に格納されています

>>428◆ucf6bhGcw2 (P)
>>424>>431◆Kumap6680. (森) ウしさんは見た!<>sage<>03/09/09 17:56 KAxtKvLN<> <br> <br>   、ー'´    <><>renge05.tezukayama-u.ac.jp<>160.244.86.25<>

以下省略 /test/read.cgi/tech/1019033323/">★スマホ版★ 掲示板に戻る 全部 前100 次100 最新50

read.cgi ver 05.04.00 2017/10/04 Walang Kapalit ★
FOX ★ DSO(Dynamic Shared Object)