/* NAME
* eipd - simulate the ecological iterated Prisoner's Dilemma
* NOTES
* None.
* PAYOFFS
* The payoff matrix for the Prisoner's Dilemma game is usually
* expressed as:
* Player B's Move
* +-----------+-----------+
* Player A's Move | cooperate | defect |
* +-----------+-----------+-----------+
* | cooperate | CC, CC | CD, DC |
* +-----------+-----------+-----------+
* | defect | DC, CD | DD, DD |
* +-----------+-----------+-----------+
*
* where the table entries are (A's payoff, B's payoff) and
* CC, CD, DC, and DD are the reward, sucker, temptation,
* and punish payoffs, respectively. For each of these four
* outcomes you will probably want the payoffs to reflect the
* relationships:
*
* (DC > CC > DD > CD) and ((CD + DC) / 2 < CC).
* MISCELLANY
* random noise (via the -noise option) manifests itself as a
* cell making a randomly selected move in a single round. In
* this case, both the cell whose action was altered as well as
* that cell's opponents "remember" what the random move was on
* the next round.
*
* During each time step, every strategy plays against every
* other strategy as well as against itself.
*
* The initial population levels for all strategies will be
* normalized, so the scaling of the option values is irrelevant.
* BUGS
* No sanity checks are performed to make sure that any of the
* options make sense.
* AUTHOR
* Copyright (c) 1997, Gary William Flake.
*
* Permission granted for any use according to the standard GNU
* ``copyleft'' agreement provided that the author's comments are
* neither modified nor removed. No warranty is given or implied.
*/
#include
#include
#include
#include "misc.h"
#define ALLC 0
#define TFT 1
#define RAND 2
#define PAV 3
#define ALLD 4
#define NUMSTRATS 5
int steps = 100000, rounds = 10, seed = 0;
double CC = 3, CD = 0, DC = 5, DD = 1, rcp = 0.5, noise = 0;
double Irand = 0.2, Iallc = 0.2, Ialld = 0.2 , Itft = 0.2, Ipav = 0.2;
double pops[NUMSTRATS], scores[NUMSTRATS];
char help_string[] = "\
The ecological iterated Prisoner's Dilemma is simulated over time \
according to the specified parameters. At every time step the population \
of each strategy is calculated as a function of the expected scores \
earned against all strategies weighted by the populations of the \
opponents. Possible strategies include 'Always Cooperate,' 'Always Defect,' \
'Random,' 'Pavlov,' and 'Tit-for-Tat.'\
";
OPTION options[] = {
{ "-steps", OPT_INT, &steps, "Number of steps to simulate." },
{ "-rounds", OPT_INT, &rounds, "Number of rounds per step." },
{ "-seed", OPT_INT, &seed, "Random seed for initial state." },
{ "-CC", OPT_DOUBLE, &CC, "Reward Payoff." },
{ "-CD", OPT_DOUBLE, &CD, "Sucker Payoff." },
{ "-DC", OPT_DOUBLE, &DC, "Temptation Payoff." },
{ "-DD", OPT_DOUBLE, &DD, "Punish Payoff." },
{ "-Iallc", OPT_DOUBLE, &Iallc, "Initial population of All-C." },
{ "-Itft", OPT_DOUBLE, &Itft, "Initial population of TFT." },
{ "-Irand", OPT_DOUBLE, &Irand, "Initial population of Random." },
{ "-Ipav", OPT_DOUBLE, &Ipav, "Initial population of Pavlov." },
{ "-Ialld", OPT_DOUBLE, &Ialld, "Initial population of All-D." },
{ "-rcp", OPT_DOUBLE, &rcp, "Probability of C for Random strategy." },
{ "-noise", OPT_DOUBLE, &noise, "Probability of noise." },
{ NULL, OPT_NULL, NULL, NULL }
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* This function returns the play made by a strategy given the last
move of his opponent and himself. */
int pd(int strat, int last_him, int last_me)
{
/* First see if a random play is appropriate. */
if(noise > 0 && random_range(0, 1) < noise)
return(random_range(0, 1) < 0.5 ? 0 : 1);
/* Always cooperate, regardless. */
if(strat == ALLC)
return(0);
/* Since the histories are initialize with all cooperation,
* Tit-for-Tat simply plays whatever his opponent did the last
* round.
*/
if(strat == TFT)
return(last_him);
/* Random cooperates with probability rcp and defect other times. */
if(strat == RAND)
return((random_range(0,1) < rcp) ? 0 : 1);
/* Pavlov does what he did if he wasn't punished, but does what he
* didn't do when he was punished.
*/
if(strat == PAV)
return(last_him ? !last_me : last_me);
/* Always Defect is just a mean bastard! */
if(strat == ALLD)
return(1);
return(0);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Returns the score earned by player one if he played s1 and his
opponent played s2. */
double pay(int s1, int s2)
{
if(s1) {
if(s2) return(DD);
else return(DC);
}
else {
if(s2) return(CD);
else return(CC);
}
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int main(int argc, char **argv)
{
int i, j, k, l, acthim, actme, lasthim, lastme;
double sum, payout;
get_options(argc, argv, options, help_string);
srandom(seed);
/* Normalize all of the populations so that they equal probabilities,
* Then accumulate them so that we can do roulette selection.
*/
sum = Iallc + Ialld + Irand + Itft + Ipav;
pops[ALLC] = Iallc / sum;
pops[TFT] = Itft / sum;
pops[RAND] = Irand / sum;
pops[PAV] = Ipav / sum;
pops[ALLD] = Ialld / sum;
/* For each time step... */
for(i = 0; i < steps; i++) {
/* Print out the normalized population levels. */
for(j = 0; j < NUMSTRATS; j++)
printf("%f\t", pops[j]);
printf("\n");
/* For each strategy... */
for(j = 0; j < NUMSTRATS; j++) {
/* Zero out the score. */
scores[j] = 0;
/* Skip any strategy that is completely dead. */
if(pops[j] == 0.0) continue;
/* For every strategy (again) ... */
for(k = 0; k < NUMSTRATS; k++) {
/* Set running sum to 0. */
sum = 0;
/* Assume cooperation on previous move for first game. */
lasthim = lastme = 0;
/* For every round. */
for(l = 0; l < rounds; l++) {
/* Get two actions for the two players. */
actme = pd(j, lasthim, lastme);
acthim = pd(k, lastme, lasthim);
/* Get the payout. */
payout = pay(actme, acthim);
/* Same the last move for the next game. */
lastme = actme; lasthim = acthim;
/* Keep a running total of the scores. */
sum += payout;
}
/* Set the score weighted by the population of the opponents. */
scores[j] += sum * pops[k];
}
}
/* Get the sum of the populations and renormalize. */
sum = 0;
for(j = 0; j < NUMSTRATS; j++) {
pops[j] = pops[j] * scores[j];
sum += pops[j];
}
for(j = 0; j < NUMSTRATS; j++)
pops[j] /= sum;
}
exit(0);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */