952 lines
25 KiB
C
952 lines
25 KiB
C
|
/* -*- Mode: C; tab-width: 4 -*- */
|
||
|
/* dilemma --- Lloyd's Prisoner's Dilemma Simulation */
|
||
|
|
||
|
#if !defined( lint ) && !defined( SABER )
|
||
|
static const char sccsid[] = "@(#)dilemma.c 5.00 2000/11/01 xlockmore";
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*-
|
||
|
* Copyright (c) 1997 by David Bagley.
|
||
|
*
|
||
|
* Permission to use, copy, modify, and distribute this software and its
|
||
|
* documentation for any purpose and without fee is hereby granted,
|
||
|
* provided that the above copyright notice appear in all copies and that
|
||
|
* both that copyright notice and this permission notice appear in
|
||
|
* supporting documentation.
|
||
|
*
|
||
|
* This file is provided AS IS with no warranties of any kind. The author
|
||
|
* shall have no liability with respect to the infringement of copyrights,
|
||
|
* trade secrets or any patents by this file or any part thereof. In no
|
||
|
* event will the author be liable for any lost revenue or profits or
|
||
|
* other special, indirect and consequential damages.
|
||
|
*
|
||
|
* Revision History:
|
||
|
* 01-Nov-2000: Allocation checks
|
||
|
* 20-Oct-1997: Computing Bouts of the Prisoner's Dilemma by Alun L. Lloyd
|
||
|
* Scientific American Magazine June 1995
|
||
|
* Used voters.c as a guide.
|
||
|
*/
|
||
|
|
||
|
/*-
|
||
|
* Opponent's Strategy
|
||
|
*
|
||
|
* Cooperate Defect
|
||
|
* -----------------------
|
||
|
* | | |
|
||
|
* Cooperate | 1 | 0 |
|
||
|
* Player's | | |
|
||
|
* Strategy |-----------+-----------|
|
||
|
* | | |
|
||
|
* Defect | b | 0 |
|
||
|
* | | |
|
||
|
* -----------------------
|
||
|
*
|
||
|
* The Payoff Matrix
|
||
|
*
|
||
|
* An interesting value of "b" for a 8 neighbor grid is 1.85
|
||
|
* What does b stand for? "bonus"?
|
||
|
* Cells get 1 if they and their opponent cooperates.
|
||
|
* Cells get b if they cheat and their opponent cooperates.
|
||
|
* Cells get 0 in the 2 other cases.
|
||
|
* If b is greater then a cell should always cheat except
|
||
|
* they have to live with their neighbor... so on the next go around
|
||
|
* their neighbor might not see any benefit in cooperating.
|
||
|
* Cells add up the previous results of their neighbors
|
||
|
* and decide if its their best strategy is to cheat or not to cheat.
|
||
|
*
|
||
|
* I have noticed round off errors I have not as yet tracked them down.
|
||
|
* Try
|
||
|
* -bonus 1.99 -neighbors 12 -size 10
|
||
|
* -bonus 241 -neighbors 6 -size 8
|
||
|
* -bonus 1.71 -neighbors 4 -size 4
|
||
|
*/
|
||
|
|
||
|
#ifdef STANDALONE
|
||
|
#define MODE_dilemma
|
||
|
#define PROGCLASS "Dilemma"
|
||
|
#define HACK_INIT init_dilemma
|
||
|
#define HACK_DRAW draw_dilemma
|
||
|
#define dilemma_opts xlockmore_opts
|
||
|
#define DEFAULTS "*delay: 200000 \n" \
|
||
|
"*batchcount: -2 \n" \
|
||
|
"*cycles: 1000 \n" \
|
||
|
"*size: 0 \n" \
|
||
|
"*ncolors: 6 \n" \
|
||
|
"*neighbors: 0 \n"
|
||
|
#include "xlockmore.h" /* in xscreensaver distribution */
|
||
|
#define UNIFORM_COLORS
|
||
|
#define BRIGHT_COLORS
|
||
|
#define SMOOTH_COLORS
|
||
|
#else /* STANDALONE */
|
||
|
#include "xlock.h" /* in xlockmore distribution */
|
||
|
#endif /* STANDALONE */
|
||
|
#include "automata.h"
|
||
|
|
||
|
#ifdef MODE_dilemma
|
||
|
|
||
|
/*-
|
||
|
* neighbors of 0 randomizes it between 3, 4, 6, 8, 9, and 12.
|
||
|
*/
|
||
|
#define DEF_NEIGHBORS "0" /* choose random value */
|
||
|
#define DEF_BONUS "1.85"
|
||
|
#define DEF_CONSCIOUS "True"
|
||
|
|
||
|
static int neighbors;
|
||
|
static float bonus;
|
||
|
static Bool conscious;
|
||
|
|
||
|
static XrmOptionDescRec opts[] =
|
||
|
{
|
||
|
{(char *) "-neighbors", (char *) ".dilemma.neighbors", XrmoptionSepArg, (caddr_t) NULL},
|
||
|
{(char *) "-bonus", (char *) ".dilemma.bonus", XrmoptionSepArg, (caddr_t) NULL},
|
||
|
{(char *) "-conscious", (char *) ".dilemma.conscious", XrmoptionNoArg, (caddr_t) "on"},
|
||
|
{(char *) "+conscious", (char *) ".dilemma.conscious", XrmoptionNoArg, (caddr_t) "off"}
|
||
|
};
|
||
|
static argtype vars[] =
|
||
|
{
|
||
|
{(void *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int},
|
||
|
{(void *) & bonus, (char *) "bonus", (char *) "Bonus", (char *) DEF_BONUS, t_Float},
|
||
|
{(void *) & conscious, (char *) "conscious", (char *) "Conscious", (char *) DEF_CONSCIOUS, t_Bool}
|
||
|
};
|
||
|
static OptionStruct desc[] =
|
||
|
{
|
||
|
{(char *) "-neighbors num", (char *) "squares 4 or 8, hexagons 6, triangles 3, 9 or 12"},
|
||
|
{(char *) "-bonus value", (char *) "bonus for cheating... between 1.0 and 4.0"},
|
||
|
{(char *) "-/+conscious", (char *) "turn on/off self-awareness"}
|
||
|
};
|
||
|
|
||
|
ModeSpecOpt dilemma_opts =
|
||
|
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
|
||
|
|
||
|
#ifdef USE_MODULES
|
||
|
ModStruct dilemma_description =
|
||
|
{"dilemma", "init_dilemma", "draw_dilemma", "release_dilemma",
|
||
|
"refresh_dilemma", "init_dilemma", (char *) NULL, &dilemma_opts,
|
||
|
200000, -2, 1000, 0, 64, 1.0, "",
|
||
|
"Shows Lloyd's Prisoner's Dilemma simulation", 0, NULL};
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/* Better bitmaps needed :) */
|
||
|
#include "bitmaps/cooperat.xbm" /* age > 1 then blue, age = 1 then green */
|
||
|
#include "bitmaps/defect.xbm" /* age > 1 then red, age = 1 then yellow */
|
||
|
|
||
|
#define DEFECTOR 0
|
||
|
#define COOPERATOR 1
|
||
|
#define COLORS 4
|
||
|
#define BLUE (45 * MI_NPIXELS(mi) / 64) /* COOPERATING, was cooperating */
|
||
|
#define GREEN (23 * MI_NPIXELS(mi) / 64) /* COOPERATING, was defecting */
|
||
|
#define YELLOW (MI_NPIXELS(mi) / 6) /* DEFECTING, was cooperating */
|
||
|
#define RED 0 /* DEFECTING, was defecting */
|
||
|
#define MINDEFECT 1
|
||
|
#define BITMAPS 2
|
||
|
#define MINGRIDSIZE 16
|
||
|
#define MINSIZE 10
|
||
|
#define FACTOR 10
|
||
|
#define NEIGHBORKINDS 6
|
||
|
#define REDRAWSTEP 2000 /* How many cells to draw per cycle */
|
||
|
#define ROUND_FLOAT(x,a) ((float) ((int) ((x) / (a) + 0.5)) * (a))
|
||
|
|
||
|
static XImage logo[BITMAPS] =
|
||
|
{
|
||
|
{0, 0, 0, XYBitmap, (char *) cooperat_bits, LSBFirst, 8, LSBFirst, 8, 1},
|
||
|
{0, 0, 0, XYBitmap, (char *) defect_bits, LSBFirst, 8, LSBFirst, 8, 1}
|
||
|
};
|
||
|
|
||
|
/* Dilemma data */
|
||
|
|
||
|
/* Singly linked list */
|
||
|
typedef struct _CellList {
|
||
|
XPoint pt;
|
||
|
struct _CellList *next;
|
||
|
} CellList;
|
||
|
|
||
|
typedef struct {
|
||
|
int defectors; /* portion of defectors */
|
||
|
float pm[2][2]; /* payoff matrix */
|
||
|
unsigned long colors[2][2];
|
||
|
CellList *cellList[COLORS];
|
||
|
char *s, *sn; /* cell strategies */
|
||
|
float *payoff;
|
||
|
int initialized;
|
||
|
int xs, ys; /* Size of cooperators and defectors */
|
||
|
int xb, yb; /* Bitmap offset for cooperators and defectors */
|
||
|
int state;
|
||
|
int redrawing, redrawpos;
|
||
|
int pixelmode;
|
||
|
int generation;
|
||
|
int ncols, nrows;
|
||
|
int npositions;
|
||
|
int width, height;
|
||
|
int neighbors;
|
||
|
union {
|
||
|
XPoint hexagon[6];
|
||
|
XPoint triangle[2][3];
|
||
|
} shape;
|
||
|
} dilemmastruct;
|
||
|
|
||
|
static char plots[NEIGHBORKINDS] =
|
||
|
{
|
||
|
3, 4, 6, 8, 9, 12 /* Neighborhoods */
|
||
|
};
|
||
|
|
||
|
static dilemmastruct *dilemmas = (dilemmastruct *) NULL;
|
||
|
static int icon_width, icon_height;
|
||
|
|
||
|
static void
|
||
|
drawcell(ModeInfo * mi, int col, int row, unsigned long color, int bitmap,
|
||
|
Bool firstChange)
|
||
|
{
|
||
|
Display *display = MI_DISPLAY(mi);
|
||
|
Window window = MI_WINDOW(mi);
|
||
|
GC gc = MI_GC(mi);
|
||
|
dilemmastruct *dp = &dilemmas[MI_SCREEN(mi)];
|
||
|
unsigned long colour = (MI_NPIXELS(mi) >= COLORS) ?
|
||
|
color : MI_WHITE_PIXEL(mi);
|
||
|
|
||
|
XSetForeground(display, gc, colour);
|
||
|
if (dp->neighbors == 6) {
|
||
|
int ccol = 2 * col + !(row & 1), crow = 2 * row;
|
||
|
|
||
|
dp->shape.hexagon[0].x = dp->xb + ccol * dp->xs;
|
||
|
dp->shape.hexagon[0].y = dp->yb + crow * dp->ys;
|
||
|
if (dp->xs == 1 && dp->ys == 1)
|
||
|
XDrawPoint(display, window, gc,
|
||
|
dp->shape.hexagon[0].x, dp->shape.hexagon[0].y);
|
||
|
else if (bitmap == BITMAPS - 1)
|
||
|
XFillPolygon(display, window, gc,
|
||
|
dp->shape.hexagon, 6, Convex, CoordModePrevious);
|
||
|
else {
|
||
|
if (firstChange) {
|
||
|
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
|
||
|
XFillPolygon(display, window, gc,
|
||
|
dp->shape.hexagon, 6, Convex, CoordModePrevious);
|
||
|
XSetForeground(display, gc, colour);
|
||
|
}
|
||
|
if (dp->xs <= 6 || dp->ys <= 2)
|
||
|
XFillRectangle(display, window, gc,
|
||
|
dp->shape.hexagon[0].x - 3 * dp->xs / 4,
|
||
|
dp->shape.hexagon[0].y + dp->ys / 4, dp->xs, dp->ys);
|
||
|
else
|
||
|
XFillArc(display, window, gc,
|
||
|
dp->xb + dp->xs * ccol - 3 * dp->xs / 4,
|
||
|
dp->yb + dp->ys * crow + dp->ys / 4,
|
||
|
2 * dp->xs - 6, 2 * dp->ys - 2,
|
||
|
0, 23040);
|
||
|
}
|
||
|
} else if (dp->neighbors == 4 || dp->neighbors == 8) {
|
||
|
if (dp->pixelmode) {
|
||
|
if (bitmap == BITMAPS - 1 || (dp->xs <= 2 || dp->ys <= 2))
|
||
|
XFillRectangle(display, window, gc,
|
||
|
dp->xb + dp->xs * col, dp->yb + dp->ys * row,
|
||
|
dp->xs - (dp->xs > 3), dp->ys - (dp->ys > 3));
|
||
|
else {
|
||
|
if (firstChange) {
|
||
|
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
|
||
|
XFillRectangle(display, window, gc,
|
||
|
dp->xb + dp->xs * col, dp->yb + dp->ys * row,
|
||
|
dp->xs, dp->ys);
|
||
|
XSetForeground(display, gc, colour);
|
||
|
}
|
||
|
XFillArc(display, window, gc,
|
||
|
dp->xb + dp->xs * col, dp->yb + dp->ys * row,
|
||
|
dp->xs - 1, dp->ys - 1,
|
||
|
0, 23040);
|
||
|
}
|
||
|
} else
|
||
|
(void) XPutImage(display, window, gc,
|
||
|
&logo[bitmap], 0, 0,
|
||
|
dp->xb + dp->xs * col, dp->yb + dp->ys * row,
|
||
|
icon_width, icon_height);
|
||
|
} else { /* TRI */
|
||
|
int orient = (col + row) % 2; /* O left 1 right */
|
||
|
|
||
|
dp->shape.triangle[orient][0].x = dp->xb + col * dp->xs;
|
||
|
dp->shape.triangle[orient][0].y = dp->yb + row * dp->ys;
|
||
|
if (dp->xs <= 3 || dp->ys <= 3)
|
||
|
XDrawPoint(display, window, gc,
|
||
|
((orient) ? -1 : 1) + dp->shape.triangle[orient][0].x,
|
||
|
dp->shape.triangle[orient][0].y);
|
||
|
else {
|
||
|
if (orient)
|
||
|
dp->shape.triangle[orient][0].x += (dp->xs / 2 - 1);
|
||
|
else
|
||
|
dp->shape.triangle[orient][0].x -= (dp->xs / 2 - 1);
|
||
|
if (bitmap == BITMAPS - 1)
|
||
|
XFillPolygon(display, window, gc,
|
||
|
dp->shape.triangle[orient], 3, Convex, CoordModePrevious);
|
||
|
else {
|
||
|
if (firstChange) {
|
||
|
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
|
||
|
XFillPolygon(display, window, gc,
|
||
|
dp->shape.triangle[orient], 3, Convex, CoordModePrevious);
|
||
|
XSetForeground(display, gc, colour);
|
||
|
}
|
||
|
XFillArc(display, window, gc,
|
||
|
dp->xb + dp->xs * col - 4 * dp->xs / 5 +
|
||
|
((orient) ? dp->xs / 3 : 3 * dp->xs / 5),
|
||
|
dp->yb + dp->ys * row - dp->ys / 2 + 1, dp->ys - 3, dp->ys - 3,
|
||
|
0, 23040);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
addtolist(ModeInfo * mi, int col, int row, int state)
|
||
|
{
|
||
|
dilemmastruct *dp = &dilemmas[MI_SCREEN(mi)];
|
||
|
CellList *current;
|
||
|
|
||
|
current = dp->cellList[state];
|
||
|
dp->cellList[state] = (CellList *) malloc(sizeof (CellList));
|
||
|
dp->cellList[state]->pt.x = col;
|
||
|
dp->cellList[state]->pt.y = row;
|
||
|
dp->cellList[state]->next = current;
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
static void
|
||
|
print_state(ModeInfo * mi, int state)
|
||
|
{
|
||
|
dilemmastruct *dp = &dilemmas[MI_SCREEN(mi)];
|
||
|
CellList *locallist;
|
||
|
int i = 0;
|
||
|
|
||
|
locallist = dp->cellList[state];
|
||
|
(void) printf("state %d\n", state);
|
||
|
while (locallist) {
|
||
|
(void) printf("%d x %d, y %d\n", i,
|
||
|
locallist->pt.x, locallist->pt.y);
|
||
|
locallist = locallist->next;
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
static void
|
||
|
free_state(dilemmastruct * dp, int state)
|
||
|
{
|
||
|
CellList *current;
|
||
|
|
||
|
while (dp->cellList[state]) {
|
||
|
current = dp->cellList[state];
|
||
|
dp->cellList[state] = dp->cellList[state]->next;
|
||
|
free(current);
|
||
|
}
|
||
|
dp->cellList[state] = (CellList *) NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
free_list(dilemmastruct * dp)
|
||
|
{
|
||
|
int state;
|
||
|
|
||
|
for (state = 0; state < COLORS; state++)
|
||
|
free_state(dp, state);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
free_dilemma(dilemmastruct *dp)
|
||
|
{
|
||
|
free_list(dp);
|
||
|
if (dp->sn != NULL) {
|
||
|
free(dp->sn);
|
||
|
dp->sn = (char *) NULL;
|
||
|
}
|
||
|
if (dp->s != NULL) {
|
||
|
free(dp->s);
|
||
|
dp->s = (char *) NULL;
|
||
|
}
|
||
|
if (dp->payoff != NULL) {
|
||
|
free(dp->payoff);
|
||
|
dp->payoff = (float *) NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
alloc_dilemma(dilemmastruct *dp)
|
||
|
{
|
||
|
if ((dp->s = (char *) calloc(dp->npositions, sizeof (char))) == NULL) {
|
||
|
free_dilemma(dp);
|
||
|
return;
|
||
|
}
|
||
|
if ((dp->sn = (char *) calloc(dp->npositions, sizeof (char))) == NULL) {
|
||
|
free_dilemma(dp);
|
||
|
return;
|
||
|
}
|
||
|
if ((dp->payoff = (float *) calloc(dp->npositions,
|
||
|
sizeof (float))) == NULL) {
|
||
|
free_dilemma(dp);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
neighbor_position(dilemmastruct * dp, int col, int row, int dir)
|
||
|
{
|
||
|
if (dp->neighbors == 6) {
|
||
|
switch (dir) {
|
||
|
case 0:
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
break;
|
||
|
case 60:
|
||
|
if (!(row & 1))
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
row = (!row) ? dp->nrows - 1 : row - 1;
|
||
|
break;
|
||
|
case 120:
|
||
|
if (row & 1)
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
row = (!row) ? dp->nrows - 1 : row - 1;
|
||
|
break;
|
||
|
case 180:
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
break;
|
||
|
case 240:
|
||
|
if (row & 1)
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
row = (row + 1 == dp->nrows) ? 0 : row + 1;
|
||
|
break;
|
||
|
case 300:
|
||
|
if (!(row & 1))
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
row = (row + 1 == dp->nrows) ? 0 : row + 1;
|
||
|
break;
|
||
|
default:
|
||
|
(void) fprintf(stderr, "wrong direction %d\n", dir);
|
||
|
}
|
||
|
} else if (dp->neighbors == 4 || dp->neighbors == 8) {
|
||
|
switch (dir) {
|
||
|
case 0:
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
break;
|
||
|
case 45:
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
row = (!row) ? dp->nrows - 1 : row - 1;
|
||
|
break;
|
||
|
case 90:
|
||
|
row = (!row) ? dp->nrows - 1 : row - 1;
|
||
|
break;
|
||
|
case 135:
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
row = (!row) ? dp->nrows - 1 : row - 1;
|
||
|
break;
|
||
|
case 180:
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
break;
|
||
|
case 225:
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
row = (row + 1 == dp->nrows) ? 0 : row + 1;
|
||
|
break;
|
||
|
case 270:
|
||
|
row = (row + 1 == dp->nrows) ? 0 : row + 1;
|
||
|
break;
|
||
|
case 315:
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
row = (row + 1 == dp->nrows) ? 0 : row + 1;
|
||
|
break;
|
||
|
default:
|
||
|
(void) fprintf(stderr, "wrong direction %d\n", dir);
|
||
|
}
|
||
|
} else { /* TRI */
|
||
|
if ((col + row) % 2) { /* right */
|
||
|
switch (dir) {
|
||
|
case 0:
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
break;
|
||
|
case 30:
|
||
|
case 40:
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
row = (row + 1 == dp->nrows) ? 0 : row + 1;
|
||
|
break;
|
||
|
case 60:
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
if (row + 1 == dp->nrows)
|
||
|
row = 1;
|
||
|
else if (row + 2 == dp->nrows)
|
||
|
row = 0;
|
||
|
else
|
||
|
row = row + 2;
|
||
|
break;
|
||
|
case 80:
|
||
|
case 90:
|
||
|
if (row + 1 == dp->nrows)
|
||
|
row = 1;
|
||
|
else if (row + 2 == dp->nrows)
|
||
|
row = 0;
|
||
|
else
|
||
|
row = row + 2;
|
||
|
break;
|
||
|
case 120:
|
||
|
row = (row + 1 == dp->nrows) ? 0 : row + 1;
|
||
|
break;
|
||
|
case 150:
|
||
|
case 160:
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
row = (row + 1 == dp->nrows) ? 0 : row + 1;
|
||
|
break;
|
||
|
case 180:
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
break;
|
||
|
case 200:
|
||
|
case 210:
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
row = (!row) ? dp->nrows - 1 : row - 1;
|
||
|
break;
|
||
|
case 240:
|
||
|
row = (!row) ? dp->nrows - 1 : row - 1;
|
||
|
break;
|
||
|
case 270:
|
||
|
case 280:
|
||
|
if (!row)
|
||
|
row = dp->nrows - 2;
|
||
|
else if (!(row - 1))
|
||
|
row = dp->nrows - 1;
|
||
|
else
|
||
|
row = row - 2;
|
||
|
|
||
|
break;
|
||
|
case 300:
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
if (!row)
|
||
|
row = dp->nrows - 2;
|
||
|
else if (!(row - 1))
|
||
|
row = dp->nrows - 1;
|
||
|
else
|
||
|
row = row - 2;
|
||
|
break;
|
||
|
case 320:
|
||
|
case 330:
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
row = (!row) ? dp->nrows - 1 : row - 1;
|
||
|
break;
|
||
|
default:
|
||
|
(void) fprintf(stderr, "wrong direction %d\n", dir);
|
||
|
}
|
||
|
} else { /* left */
|
||
|
switch (dir) {
|
||
|
case 0:
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
break;
|
||
|
case 30:
|
||
|
case 40:
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
row = (!row) ? dp->nrows - 1 : row - 1;
|
||
|
break;
|
||
|
case 60:
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
if (!row)
|
||
|
row = dp->nrows - 2;
|
||
|
else if (row == 1)
|
||
|
row = dp->nrows - 1;
|
||
|
else
|
||
|
row = row - 2;
|
||
|
break;
|
||
|
case 80:
|
||
|
case 90:
|
||
|
if (!row)
|
||
|
row = dp->nrows - 2;
|
||
|
else if (row == 1)
|
||
|
row = dp->nrows - 1;
|
||
|
else
|
||
|
row = row - 2;
|
||
|
break;
|
||
|
case 120:
|
||
|
row = (!row) ? dp->nrows - 1 : row - 1;
|
||
|
break;
|
||
|
case 150:
|
||
|
case 160:
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
row = (!row) ? dp->nrows - 1 : row - 1;
|
||
|
break;
|
||
|
case 180:
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
break;
|
||
|
case 200:
|
||
|
case 210:
|
||
|
col = (!col) ? dp->ncols - 1 : col - 1;
|
||
|
row = (row + 1 == dp->nrows) ? 0 : row + 1;
|
||
|
break;
|
||
|
case 240:
|
||
|
row = (row + 1 == dp->nrows) ? 0 : row + 1;
|
||
|
break;
|
||
|
case 270:
|
||
|
case 280:
|
||
|
if (row + 1 == dp->nrows)
|
||
|
row = 1;
|
||
|
else if (row + 2 == dp->nrows)
|
||
|
row = 0;
|
||
|
else
|
||
|
row = row + 2;
|
||
|
break;
|
||
|
case 300:
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
if (row + 1 == dp->nrows)
|
||
|
row = 1;
|
||
|
else if (row + 2 == dp->nrows)
|
||
|
row = 0;
|
||
|
else
|
||
|
row = row + 2;
|
||
|
break;
|
||
|
case 320:
|
||
|
case 330:
|
||
|
col = (col + 1 == dp->ncols) ? 0 : col + 1;
|
||
|
row = (row + 1 == dp->nrows) ? 0 : row + 1;
|
||
|
break;
|
||
|
default:
|
||
|
(void) fprintf(stderr, "wrong direction %d\n", dir);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return row * dp->ncols + col;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
draw_state(ModeInfo * mi, int state)
|
||
|
{
|
||
|
dilemmastruct *dp = &dilemmas[MI_SCREEN(mi)];
|
||
|
CellList *current;
|
||
|
|
||
|
|
||
|
current = dp->cellList[state];
|
||
|
while (current) {
|
||
|
int col = current->pt.x;
|
||
|
int row = current->pt.y;
|
||
|
int colrow = col + row * dp->ncols;
|
||
|
|
||
|
drawcell(mi, col, row,
|
||
|
dp->colors[(int) dp->sn[colrow]][(int) dp->s[colrow]],
|
||
|
dp->sn[colrow], 1);
|
||
|
if (dp->s[colrow] && !dp->sn[colrow])
|
||
|
dp->defectors--;
|
||
|
if (!dp->s[colrow] && dp->sn[colrow])
|
||
|
dp->defectors++;
|
||
|
dp->s[colrow] = dp->sn[colrow];
|
||
|
current = current->next;
|
||
|
}
|
||
|
free_state(dp, state);
|
||
|
XFlush(MI_DISPLAY(mi));
|
||
|
}
|
||
|
|
||
|
void
|
||
|
init_dilemma(ModeInfo * mi)
|
||
|
{
|
||
|
int size = MI_SIZE(mi);
|
||
|
int i, col, row, colrow, mrow;
|
||
|
dilemmastruct *dp;
|
||
|
|
||
|
if (dilemmas == NULL) {
|
||
|
if ((dilemmas = (dilemmastruct *) calloc(MI_NUM_SCREENS(mi),
|
||
|
sizeof (dilemmastruct))) == NULL)
|
||
|
return;
|
||
|
}
|
||
|
dp = &dilemmas[MI_SCREEN(mi)];
|
||
|
|
||
|
dp->generation = 0;
|
||
|
dp->redrawing = 0;
|
||
|
dp->state = 0;
|
||
|
free_dilemma(dp);
|
||
|
|
||
|
if (!dp->initialized) { /* Genesis */
|
||
|
icon_width = cooperat_width;
|
||
|
icon_height = cooperat_height;
|
||
|
dp->initialized = 1;
|
||
|
for (i = 0; i < BITMAPS; i++) {
|
||
|
logo[i].width = icon_width;
|
||
|
logo[i].height = icon_height;
|
||
|
logo[i].bytes_per_line = (icon_width + 7) / 8;
|
||
|
}
|
||
|
}
|
||
|
dp->width = MI_WIDTH(mi);
|
||
|
dp->height = MI_HEIGHT(mi);
|
||
|
|
||
|
for (i = 0; i < NEIGHBORKINDS; i++) {
|
||
|
if (neighbors == plots[i]) {
|
||
|
dp->neighbors = neighbors;
|
||
|
break;
|
||
|
}
|
||
|
if (i == NEIGHBORKINDS - 1) {
|
||
|
#if 0
|
||
|
dp->neighbors = plots[NRAND(NEIGHBORKINDS)];
|
||
|
dp->neighbors = (LRAND() & 1) ? 4 : 8;
|
||
|
#else
|
||
|
dp->neighbors = 8;
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (dp->neighbors == 6) {
|
||
|
int nccols, ncrows, sides;
|
||
|
|
||
|
if (dp->width < 2)
|
||
|
dp->width = 2;
|
||
|
if (dp->height < 4)
|
||
|
dp->height = 4;
|
||
|
if (size < -MINSIZE)
|
||
|
dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
|
||
|
MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
|
||
|
else if (size < MINSIZE) {
|
||
|
if (!size)
|
||
|
dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
|
||
|
else
|
||
|
dp->ys = MINSIZE;
|
||
|
} else
|
||
|
dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
|
||
|
MINGRIDSIZE));
|
||
|
dp->xs = dp->ys;
|
||
|
dp->pixelmode = True;
|
||
|
nccols = MAX(dp->width / dp->xs - 2, 2);
|
||
|
ncrows = MAX(dp->height / dp->ys - 1, 2);
|
||
|
dp->ncols = nccols / 2;
|
||
|
dp->nrows = 2 * (ncrows / 4);
|
||
|
dp->xb = (dp->width - dp->xs * nccols) / 2 + dp->xs / 2;
|
||
|
dp->yb = (dp->height - dp->ys * (ncrows / 2) * 2) / 2 + dp->ys - 2;
|
||
|
for (sides = 0; sides < 6; sides++) {
|
||
|
dp->shape.hexagon[sides].x = (dp->xs - 1) * hexagonUnit[sides].x;
|
||
|
dp->shape.hexagon[sides].y =
|
||
|
((dp->ys - 1) * hexagonUnit[sides].y / 2) * 4 / 3;
|
||
|
}
|
||
|
} else if (dp->neighbors == 4 || dp->neighbors == 8) {
|
||
|
if (dp->width < 2)
|
||
|
dp->width = 2;
|
||
|
if (dp->height < 2)
|
||
|
dp->height = 2;
|
||
|
if (size == 0 ||
|
||
|
MINGRIDSIZE * size > dp->width || MINGRIDSIZE * size > dp->height) {
|
||
|
if (dp->width > MINGRIDSIZE * icon_width &&
|
||
|
dp->height > MINGRIDSIZE * icon_height) {
|
||
|
dp->pixelmode = False;
|
||
|
dp->xs = icon_width;
|
||
|
dp->ys = icon_height;
|
||
|
} else {
|
||
|
dp->pixelmode = True;
|
||
|
dp->xs = dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) /
|
||
|
MINGRIDSIZE);
|
||
|
}
|
||
|
} else {
|
||
|
dp->pixelmode = True;
|
||
|
if (size < -MINSIZE)
|
||
|
dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
|
||
|
MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
|
||
|
else if (size < MINSIZE)
|
||
|
dp->ys = MINSIZE;
|
||
|
else
|
||
|
dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
|
||
|
MINGRIDSIZE));
|
||
|
dp->xs = dp->ys;
|
||
|
}
|
||
|
dp->ncols = MAX(dp->width / dp->xs, 2);
|
||
|
dp->nrows = MAX(dp->height / dp->ys, 2);
|
||
|
dp->xb = (dp->width - dp->xs * dp->ncols) / 2;
|
||
|
dp->yb = (dp->height - dp->ys * dp->nrows) / 2;
|
||
|
} else { /* TRI */
|
||
|
int orient, sides;
|
||
|
|
||
|
if (dp->width < 2)
|
||
|
dp->width = 2;
|
||
|
if (dp->height < 2)
|
||
|
dp->height = 2;
|
||
|
if (size < -MINSIZE)
|
||
|
dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
|
||
|
MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
|
||
|
else if (size < MINSIZE) {
|
||
|
if (!size)
|
||
|
dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
|
||
|
else
|
||
|
dp->ys = MINSIZE;
|
||
|
} else
|
||
|
dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
|
||
|
MINGRIDSIZE));
|
||
|
dp->xs = (int) (1.52 * dp->ys);
|
||
|
dp->pixelmode = True;
|
||
|
dp->ncols = (MAX(dp->width / dp->xs - 1, 2) / 2) * 2;
|
||
|
dp->nrows = (MAX(dp->height / dp->ys - 1, 2) / 2) * 2;
|
||
|
dp->xb = (dp->width - dp->xs * dp->ncols) / 2 + dp->xs / 2;
|
||
|
dp->yb = (dp->height - dp->ys * dp->nrows) / 2 + dp->ys / 2;
|
||
|
for (orient = 0; orient < 2; orient++) {
|
||
|
for (sides = 0; sides < 3; sides++) {
|
||
|
dp->shape.triangle[orient][sides].x =
|
||
|
(dp->xs - 2) * triangleUnit[orient][sides].x;
|
||
|
dp->shape.triangle[orient][sides].y =
|
||
|
(dp->ys - 2) * triangleUnit[orient][sides].y;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dp->npositions = dp->ncols * dp->nrows;
|
||
|
|
||
|
dp->pm[0][0] = 1, dp->pm[0][1] = 0;
|
||
|
if (bonus < 1.0 || bonus > 4.0)
|
||
|
dp->pm[1][0] = 1.85;
|
||
|
else
|
||
|
dp->pm[1][0] = bonus;
|
||
|
dp->pm[1][1] = 0;
|
||
|
|
||
|
if (MI_NPIXELS(mi) >= COLORS) {
|
||
|
|
||
|
dp->colors[0][0] = MI_PIXEL(mi, BLUE); /* COOPERATING, was cooperating */
|
||
|
dp->colors[0][1] = MI_PIXEL(mi, GREEN); /* COOPERATING, was defecting */
|
||
|
dp->colors[1][0] = MI_PIXEL(mi, YELLOW); /* DEFECTING, was cooperating */
|
||
|
dp->colors[1][1] = MI_PIXEL(mi, RED); /* DEFECTING, was defecting */
|
||
|
} else {
|
||
|
dp->colors[0][0] = MI_WHITE_PIXEL(mi);
|
||
|
dp->colors[0][1] = MI_WHITE_PIXEL(mi);
|
||
|
dp->colors[1][0] = MI_WHITE_PIXEL(mi);
|
||
|
dp->colors[1][1] = MI_WHITE_PIXEL(mi);
|
||
|
}
|
||
|
alloc_dilemma(dp);
|
||
|
if (dp->s == NULL)
|
||
|
return;
|
||
|
MI_CLEARWINDOW(mi);
|
||
|
|
||
|
dp->defectors = MI_COUNT(mi);
|
||
|
if (dp->defectors < -MINDEFECT) {
|
||
|
dp->defectors = NRAND(-dp->defectors - MINDEFECT + 1) + MINDEFECT;
|
||
|
} else if (dp->defectors < MINDEFECT)
|
||
|
dp->defectors = MINDEFECT;
|
||
|
if (dp->defectors > dp->npositions)
|
||
|
dp->defectors = dp->npositions;
|
||
|
|
||
|
for (i = 0; i < dp->defectors; i++) {
|
||
|
do {
|
||
|
colrow = NRAND(dp->npositions);
|
||
|
} while (dp->sn[colrow]);
|
||
|
dp->sn[colrow] = 1;
|
||
|
}
|
||
|
#if 0 /* if p was a float... */
|
||
|
mrow = 0;
|
||
|
for (row = 0; row < dp->nrows; row++) {
|
||
|
for (col = 0; col < dp->ncols; col++) {
|
||
|
dp->sn[col + mrow] = ((float) LRAND() / MAXRAND < dp->p);
|
||
|
}
|
||
|
mrow += dp->ncols;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
dp->defectors = 0;
|
||
|
|
||
|
/* Show initial state... real important for debugging */
|
||
|
mrow = 0;
|
||
|
for (row = 0; row < dp->nrows; ++row) {
|
||
|
for (col = 0; col < dp->ncols; ++col) {
|
||
|
addtolist(mi, col, row,
|
||
|
dp->sn[col + mrow] * BITMAPS + dp->s[col + mrow]);
|
||
|
}
|
||
|
mrow += dp->ncols;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
draw_dilemma(ModeInfo * mi)
|
||
|
{
|
||
|
int col, row, mrow, colrow, n, i;
|
||
|
dilemmastruct *dp;
|
||
|
|
||
|
if (dilemmas == NULL)
|
||
|
return;
|
||
|
dp = &dilemmas[MI_SCREEN(mi)];
|
||
|
if (dp->s == NULL)
|
||
|
return;
|
||
|
|
||
|
MI_IS_DRAWN(mi) = True;
|
||
|
|
||
|
if (dp->state >= 2 * COLORS) {
|
||
|
|
||
|
for (col = 0; col < dp->ncols; col++) {
|
||
|
for (row = 0; row < dp->nrows; row++) {
|
||
|
colrow = col + row * dp->ncols;
|
||
|
if (conscious)
|
||
|
dp->payoff[colrow] =
|
||
|
dp->pm[(int) dp->s[colrow]][(int) dp->s[colrow]];
|
||
|
else
|
||
|
dp->payoff[colrow] = 0.0;
|
||
|
for (n = 0; n < dp->neighbors; n++)
|
||
|
dp->payoff[colrow] +=
|
||
|
dp->pm[(int) dp->s[colrow]][(int)
|
||
|
dp->s[neighbor_position(dp,
|
||
|
col, row, n * 360 / dp->neighbors)]];
|
||
|
|
||
|
}
|
||
|
}
|
||
|
for (row = 0; row < dp->nrows; row++) {
|
||
|
for (col = 0; col < dp->ncols; col++) {
|
||
|
float hp;
|
||
|
int position;
|
||
|
|
||
|
colrow = col + row * dp->ncols;
|
||
|
hp = dp->payoff[colrow];
|
||
|
dp->sn[colrow] = dp->s[colrow];
|
||
|
for (n = 0; n < dp->neighbors; n++) {
|
||
|
position = neighbor_position(dp, col, row, n * 360 / dp->neighbors);
|
||
|
if (ROUND_FLOAT(dp->payoff[position], 0.001) >
|
||
|
ROUND_FLOAT(hp, 0.001)) {
|
||
|
hp = dp->payoff[position];
|
||
|
dp->sn[colrow] = dp->s[position];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
mrow = 0;
|
||
|
for (row = 0; row < dp->nrows; row++) {
|
||
|
for (col = 0; col < dp->ncols; col++) {
|
||
|
addtolist(mi, col, row,
|
||
|
dp->sn[col + mrow] * BITMAPS + dp->s[col + mrow]);
|
||
|
}
|
||
|
mrow += dp->ncols;
|
||
|
}
|
||
|
|
||
|
if (++dp->generation > MI_CYCLES(mi) ||
|
||
|
dp->defectors == dp->npositions || dp->defectors == 0)
|
||
|
init_dilemma(mi);
|
||
|
dp->state = 0;
|
||
|
} else {
|
||
|
if (dp->state < COLORS) {
|
||
|
draw_state(mi, dp->state);
|
||
|
}
|
||
|
dp->state++;
|
||
|
}
|
||
|
#if 1
|
||
|
if (dp->redrawing) {
|
||
|
for (i = 0; i < REDRAWSTEP; i++) {
|
||
|
drawcell(mi, dp->redrawpos % dp->ncols, dp->redrawpos / dp->ncols,
|
||
|
dp->colors[(int) dp->sn[dp->redrawpos]][(int) dp->s[dp->redrawpos]],
|
||
|
dp->sn[dp->redrawpos], 1);
|
||
|
if (++(dp->redrawpos) >= dp->npositions) {
|
||
|
dp->redrawing = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void
|
||
|
release_dilemma(ModeInfo * mi)
|
||
|
{
|
||
|
if (dilemmas != NULL) {
|
||
|
int screen;
|
||
|
|
||
|
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
|
||
|
free_dilemma(&dilemmas[screen]);
|
||
|
free(dilemmas);
|
||
|
dilemmas = (dilemmastruct *) NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
refresh_dilemma(ModeInfo * mi)
|
||
|
{
|
||
|
dilemmastruct *dp = &dilemmas[MI_SCREEN(mi)];
|
||
|
|
||
|
dp->redrawing = 1;
|
||
|
dp->redrawpos = 0;
|
||
|
}
|
||
|
|
||
|
#endif /* MODE_dilemma */
|