-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy patheipd.c
230 lines (190 loc) · 7.06 KB
/
eipd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/* 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 <math.h>
#include <stdio.h>
#include <stdlib.h>
#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);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */