Le dilemme du prisonnier itératif avec renoncement

Pour le maître

Ce fichier permettra au maître d'organiser facilement le tournoi entre les stratégies développées par les élèves.

Le tournoi

Conventions

moi : liste des coups du joueur courant
lui : liste des coups de l'adversaire
C : cooère
T : trahit
R : renonce

Les joueurs

Il faut mettre dans cette partie toutes les stratégies avec (éventuellement) leur descriptif. Ces stratégies seront numérotées plus tard pour le tournoi. Chaque module doit avoir comme paramètres lui_ et moi_ (dans cet ordre) et seulement ces deux paramètres. lui_ n'est pas forcément utilisé (voir p. ex. ToujoursSeul ou Aleatoire), mais il doit être présent dans la liste des paramètres pour simplifier l'écriture du code du tournoi proprement dit.

Joueur ToujoursSeul

Ne coopère jamais.

Coup1ToujoursSeul := {T};
ToujoursSeul[lui_, moi_] := 
	Module[{},
		Append[moi, T]
	];

Joueur BonnePoire

Coopère toujours.

Coup1BonnePoire := {C};
BonnePoire[lui_, moi_] := 
	Module[{},
		Append[moi, C]
	];

Joueur Aléatoire

Joue avec une probabilité égale C (coopère) ou T (trahit).

Coup1Aleatoire := {C};
Aleatoire[lui_, moi_] := 
	Module[{},
		Append[moi, {C,T}[[Random[Integer,{1,2}]]]]
	];

Joueur DonnantDonnant

Coopère seulement si l'autre joueur a coopéré au coup précédent.

Coup1DonnantDonnant := {C};
DonnantDonnant[lui_, moi_] := 
	Module[{},
		If[SameQ[Last[lui],C], Append[moi,C], Append[moi,T]]
	];

Joueur Renonce40

Donnant Donnant, mais renonce si l'adversaire joue plus de 40% de T.

Coup1Renonce40 := {C};
Renonce40[lui_, moi_] := 
	Module[{nt,long,coup=X},  
		nt=Count[lui,T];
		long=Length[lui];
		If[nt/long>0.4 && long>9,coup=R];
		If[SameQ[coup,X], DonnantDonnant[lui,moi], Append[moi,coup]]
	];

Gains

gain[lui,moi] : gain du joueur courant en fonction de son coup (moi) et du coup de l'adversaire (lui).

gain[C,C] = 3;
gain[C,T] = 5;
gain[T,C] = 0;
gain[T,T] = 1;
gain[T,R] = 2;
gain[C,R] = 2;
gain[R,R] = 2;
gain[R,C] = 2;
gain[R,T] = 2;

Renoncer

Renonce à jouer.

Renonce[moi_] := 
	Module[{},
		Append[moi, R]
	];

Le tournoi

Le petit programme ci-dessous simule la rencontre entre toutes les paires de joueurs: tout le monde joue contre tout le monde, y compris soi-même. En rouge, les bouts de code à modifier.
ns est le nombre de stratégies dans le tourmoi.
Il faut ensuite entrer les ns stratégies: d'abord le nom, puis le premier coup à jouer et enfin le nom du module.
SeedRandom est le germe du générateur pseudo-aléatoire que l'on réinitialise au début de chaque rencontre. Ainsi, le joueur Aléatoire jouera exactement les mêmes coups avec tous les joueurs.
Le 199 indique le nombre de coups par rencontre (après le premier coup, donc 200 en tout).

Le classement

Deux résultats sont donnés: le résultat des rencontres et le classement final.
Le premier tableau se lit ligne par ligne. Dans notre exemple, la 1ère ligne se lit comme suit : Bonne Poire (stratégie no 1) a marqué 600 points contre lui-même, 600 contre Donnant donnant (stratégie no 2), 144 contre Calculateur (stratégie no 3), 0 contre Toujours seul (stratégie no 4) et contre 318 Aléatoire (stratégie no 5). Total: 1662.
Le classement final est obtenu en additionnant les résultats ligne par ligne du tableau précédent. Les stratégies sont ensuite triées de la meilleure à la moins bonne (le nombre entre parenthèses indique le numéro de la stratégie).
Note: les résultats peuvent varier sensiblement selon la partie du joueur Aléatoire.

ClearAll[Score];
ns=5;
Array[Nom,ns];
Array[Coup1,ns];
Str=Array[Strategie,ns];
Resultats=Array[Score,{ns,ns}];

Nom[1] = "Bonne Poire (1)";
Coup1[1] = Coup1BonnePoire;
Strategie[1][lui_,moi_] := BonnePoire[lui, moi];

Nom[2] = "Donnant donnant (2)";
Coup1[2] = Coup1DonnantDonnant;
Strategie[2][lui_,moi_] := DonnantDonnant[lui, moi];

Nom[3] = "Renonce 40% (3)";
Coup1[3] = Coup1Renonce40;
Strategie[3][lui_,moi_] := Renonce40[lui, moi];

Nom[4] = "Toujours seul (4)";
Coup1[4] = Coup1ToujoursSeul;
Strategie[4][lui_,moi_] := ToujoursSeul[lui, moi];

Nom[5] = "Aléatoire (5)";
Coup1[5] = Coup1Aleatoire;
Strategie[5][lui_,moi_] := Aleatoire[lui, moi];

For[i=1, i<=ns,
	For[j=i, j<=ns,
		SeedRandom[999];
		joueur1 = Coup1[i];
		joueur2 = Coup1[j];
		Score[i,j] = gain[Last[joueur2],Last[joueur1]];
		If [i!=j, Score[j,i] = gain[Last[joueur1],Last[joueur2]]];
		fin = (SameQ[Last[joueur1],R] || SameQ[Last[joueur2],R]);
		aux1 = joueur1;
		aux2 = joueur2;
		Do[			
			If[fin,{aux1=Renonce[joueur1], aux2=Renonce[joueur2]},
				{
				aux1 = Strategie[i][joueur2,joueur1];
				aux2 = Strategie[j][joueur1,joueur2];
				}
			];	
			joueur1 = aux1;
			joueur2 = aux2;
			Score[i,j] += gain[Last[joueur2],Last[joueur1]];
			If [i!=j, Score[j,i] += gain[Last[joueur1],Last[joueur2]]];
			fin = (SameQ[Last[joueur1],R] || SameQ[Last[joueur2],R]),
			{199}
		];
		j++
	];
	i++
];

Print["Résultats des rencontres"]
TableForm[Resultats]

Print["Classement"]
ClearAll[Somme];
Classement=Array[Somme,{ns,2}];
For[i=1, i<=ns,
	Somme[i,1]=0;
	Somme[i,2]=Nom[i];
	For[j=1,j<=ns,Somme[i,1] += Score[i,j]; j++];
i++];
TableForm[Reverse[Sort[Classement]]]