1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* dilemma --- Lloyd's Prisoner's Dilemma Simulation */
3
4 #if 0
5 static const char sccsid[] = "@(#)dilemma.c 5.24 2007/01/18 xlockmore";
6
7 #endif
8
9 /*-
10 * Copyright (c) 1997 by David Bagley.
11 *
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
17 *
18 * This file is provided AS IS with no warranties of any kind. The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof. In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
23 *
24 * Revision History:
25 * 18-Jan-2007: Added vertical option.
26 * 01-Nov-2000: Allocation checks
27 * 20-Oct-1997: Computing Bouts of the Prisoner's Dilemma by Alun L. Lloyd
28 * Scientific American Magazine June 1995
29 * Used voters.c as a guide.
30 */
31
32 /*-
33 * Opponent's Strategy
34 *
35 * Cooperate Defect
36 * -----------------------
37 * | | |
38 * Cooperate | 1 | 0 |
39 * Player's | | |
40 * Strategy |-----------+-----------|
41 * | | |
42 * Defect | b | 0 |
43 * | | |
44 * -----------------------
45 *
46 * The Payoff Matrix
47 *
48 * An interesting value of "b" for a 8 neighbor grid is 1.85
49 * What does b stand for? "bonus"?
50 * Cells get 1 if they and their opponent cooperates.
51 * Cells get b if they cheat and their opponent cooperates.
52 * Cells get 0 in the 2 other cases.
53 * If b is greater then a cell should always cheat except
54 * they have to live with their neighbor... so on the next go around
55 * their neighbor might not see any benefit in cooperating.
56 * Cells add up the previous results of their neighbors
57 * and decide if its their best strategy is to cheat or not to cheat.
58 *
59 * I have noticed round off errors I have not as yet tracked them down.
60 * Try
61 * -bonus 1.99 -neighbors 12 -size 10
62 * -bonus 241 -neighbors 6 -size 8
63 * -bonus 1.71 -neighbors 4 -size 4
64 */
65
66 #ifdef STANDALONE
67 #define MODE_dilemma
68 #define DEFAULTS "*delay: 200000 \n" \
69 "*batchcount: -2 \n" \
70 "*cycles: 1000 \n" \
71 "*size: 0 \n" \
72 "*ncolors: 6 \n" \
73
74 # define free_dilemma 0
75 # define reshape_dilemma 0
76 # define dilemma_handle_event 0
77 #include "xlockmore.h" /* in xscreensaver distribution */
78 #define UNIFORM_COLORS
79 #define BRIGHT_COLORS
80 #define SMOOTH_COLORS
81 #else /* STANDALONE */
82 #include "xlock.h" /* in xlockmore distribution */
83 #endif /* STANDALONE */
84 #include "automata.h"
85
86 #ifdef MODE_dilemma
87
88 /*-
89 * neighbors of 0 randomizes it between 3, 4, 6, 8, 9, and 12.
90 */
91 #define DEF_NEIGHBORS "0" /* choose random value */
92 #define DEF_BONUS "1.85"
93 #define DEF_CONSCIOUS "True"
94 #define DEF_VERTICAL "False"
95
96 static int neighbors;
97 static float bonus;
98 static Bool conscious;
99 static Bool vertical;
100
101 static XrmOptionDescRec opts[] =
102 {
103 {(char *) "-neighbors", (char *) ".dilemma.neighbors", XrmoptionSepArg, (caddr_t) NULL},
104 {(char *) "-bonus", (char *) ".dilemma.bonus", XrmoptionSepArg, (caddr_t) NULL},
105 {(char *) "-conscious", (char *) ".dilemma.conscious", XrmoptionNoArg, (caddr_t) "on"},
106 {(char *) "+conscious", (char *) ".dilemma.conscious", XrmoptionNoArg, (caddr_t) "off"},
107 {(char *) "-vertical", (char *) ".dilemma.vertical", XrmoptionNoArg, (caddr_t) "on"},
108 {(char *) "+vertical", (char *) ".dilemma.vertical", XrmoptionNoArg, (caddr_t) "off"}
109 };
110 static argtype vars[] =
111 {
112 {(void *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int},
113 {(void *) & bonus, (char *) "bonus", (char *) "Bonus", (char *) DEF_BONUS, t_Float},
114 {(void *) & conscious, (char *) "conscious", (char *) "Conscious", (char *) DEF_CONSCIOUS, t_Bool},
115 {(void *) & vertical, (char *) "vertical", (char *) "Vertical", (char *) DEF_VERTICAL, t_Bool}
116 };
117 static OptionStruct desc[] =
118 {
119 {(char *) "-neighbors num", (char *) "squares 4 or 8, hexagons 6, triangles 3, 9 or 12"},
120 {(char *) "-bonus value", (char *) "bonus for cheating... between 1.0 and 4.0"},
121 {(char *) "-/+conscious", (char *) "turn on/off self-awareness"},
122 {(char *) "-/+vertical", (char *) "change orientation for hexagons and triangles"}
123 };
124
125 ENTRYPOINT ModeSpecOpt dilemma_opts =
126 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
127
128 #ifdef USE_MODULES
129 ModStruct dilemma_description =
130 {"dilemma", "init_dilemma", "draw_dilemma", "release_dilemma",
131 "refresh_dilemma", "init_dilemma", (char *) NULL, &dilemma_opts,
132 200000, -2, 1000, 0, 64, 1.0, "",
133 "Shows Lloyd's Prisoner's Dilemma simulation", 0, NULL};
134
135 #endif
136
137 /* Better bitmaps needed :) */
138 #include "bitmaps/cooperat.xbm" /* age > 1 then blue, age = 1 then green */
139 #include "bitmaps/defect.xbm" /* age > 1 then red, age = 1 then yellow */
140
141 #define DEFECTOR 0
142 #define COOPERATOR 1
143 #define COLORS 4
144 #define BLUE (45 * MI_NPIXELS(mi) / 64) /* COOPERATING, was cooperating */
145 #define GREEN (23 * MI_NPIXELS(mi) / 64) /* COOPERATING, was defecting */
146 #define YELLOW (MI_NPIXELS(mi) / 6) /* DEFECTING, was cooperating */
147 #define RED 0 /* DEFECTING, was defecting */
148 #define MINDEFECT 1
149 #define BITMAPS 2
150 #define MINGRIDSIZE 16
151 #define MINSIZE 10
152 #define FACTOR 10
153 #define NEIGHBORKINDS 2
154 #define REDRAWSTEP 2000 /* How many cells to draw per cycle */
155 #define ROUND_FLOAT(x,a) ((float) ((int) ((x) / (a) + 0.5)) * (a))
156
157 static XImage logo[BITMAPS] =
158 {
159 {0, 0, 0, XYBitmap, (char *) cooperat_bits, LSBFirst, 8, LSBFirst, 8, 1},
160 {0, 0, 0, XYBitmap, (char *) defect_bits, LSBFirst, 8, LSBFirst, 8, 1}
161 };
162
163 /* Dilemma data */
164
165 /* Singly linked list */
166 typedef struct _CellList {
167 XPoint pt;
168 struct _CellList *next;
169 } CellList;
170
171 typedef struct {
172 Bool vertical;
173 int defectors; /* portion of defectors */
174 float pm[2][2]; /* payoff matrix */
175 unsigned long colors[2][2];
176 CellList *cellList[COLORS];
177 char *s, *sn; /* cell strategies */
178 float *payoff;
179 int initialized;
180 int xs, ys; /* Size of cooperators and defectors */
181 int xb, yb; /* Bitmap offset for cooperators and defectors */
182 int state;
183 int redrawing, redrawpos;
184 int pixelmode;
185 int generation;
186 int ncols, nrows;
187 int npositions;
188 int width, height;
189 int neighbors, polygon;
190 union {
191 XPoint hexagon[7];
192 XPoint triangle[2][4];
193 } shape;
194 } dilemmastruct;
195
196 static char plots[NEIGHBORKINDS] =
197 {
198 4, 8 /* Neighborhoods: 3, 6, 9 & 12 do not really work */
199 };
200
201 static dilemmastruct *dilemmas = (dilemmastruct *) NULL;
202 static int icon_width, icon_height;
203
204 static void
drawcell(ModeInfo * mi,int col,int row,unsigned long color,int bitmap,Bool firstChange)205 drawcell(ModeInfo * mi, int col, int row, unsigned long color, int bitmap,
206 Bool firstChange)
207 {
208 Display *display = MI_DISPLAY(mi);
209 Window window = MI_WINDOW(mi);
210 GC gc = MI_GC(mi);
211 dilemmastruct *dp = &dilemmas[MI_SCREEN(mi)];
212 unsigned long colour = (MI_NPIXELS(mi) >= COLORS) ?
213 color : MI_WHITE_PIXEL(mi);
214
215 XSetForeground(display, gc, colour);
216 if (dp->neighbors == 6) {
217 int ccol = 2 * col + !(row & 1), crow = 2 * row;
218
219 if (dp->vertical) {
220 dp->shape.hexagon[0].x = dp->xb + ccol * dp->xs;
221 dp->shape.hexagon[0].y = dp->yb + crow * dp->ys;
222 } else {
223 dp->shape.hexagon[0].y = dp->xb + ccol * dp->xs;
224 dp->shape.hexagon[0].x = dp->yb + crow * dp->ys;
225 }
226 if (dp->xs == 1 && dp->ys == 1)
227 XDrawPoint(display, window, gc,
228 dp->shape.hexagon[0].x,
229 dp->shape.hexagon[0].y);
230 else if (bitmap == BITMAPS - 1)
231 XFillPolygon(display, window, gc,
232 dp->shape.hexagon, 6,
233 Convex, CoordModePrevious);
234 else {
235 int ix = 0, iy = 0, sx, sy;
236
237 if (firstChange) {
238 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
239 XFillPolygon(display, window, gc,
240 dp->shape.hexagon, 6,
241 Convex, CoordModePrevious);
242 XSetForeground(display, gc, colour);
243 }
244 if (dp->vertical) {
245 dp->shape.hexagon[0].x -= dp->xs;
246 dp->shape.hexagon[0].y += dp->ys / 4;
247 sx = 2 * dp->xs - 6;
248 sy = 2 * dp->ys - 2;
249 if (dp->xs <= 6 || dp->ys <= 2) {
250 ix = 3;
251 iy = 1;
252 } else
253 ix = 5;
254 } else {
255 dp->shape.hexagon[0].y -= dp->xs;
256 dp->shape.hexagon[0].x += dp->ys / 4;
257 sy = 2 * dp->xs - 6;
258 sx = 2 * dp->ys - 2;
259 if (dp->xs <= 6 || dp->ys <= 2) {
260 iy = 3;
261 ix = 1;
262 } else
263 iy = 5;
264 }
265 if (dp->xs <= 6 || dp->ys <= 2)
266 XFillRectangle(display, window, gc,
267 dp->shape.hexagon[0].x + ix,
268 dp->shape.hexagon[0].y + iy,
269 dp->xs, dp->ys);
270 else
271 XFillArc(display, window, gc,
272 dp->shape.hexagon[0].x + ix,
273 dp->shape.hexagon[0].y + iy,
274 sx, sy,
275 0, 23040);
276 }
277 } else if (dp->neighbors == 4 || dp->neighbors == 8) {
278 if (dp->pixelmode) {
279 if (bitmap == BITMAPS - 1 || (dp->xs <= 2 || dp->ys <= 2))
280 XFillRectangle(display, window, gc,
281 dp->xb + dp->xs * col,
282 dp->yb + dp->ys * row,
283 dp->xs - (dp->xs > 3),
284 dp->ys - (dp->ys > 3));
285 else {
286 if (firstChange) {
287 XSetForeground(display, gc,
288 MI_BLACK_PIXEL(mi));
289 XFillRectangle(display, window, gc,
290 dp->xb + dp->xs * col,
291 dp->yb + dp->ys * row,
292 dp->xs, dp->ys);
293 XSetForeground(display, gc, colour);
294 }
295 XFillArc(display, window, gc,
296 dp->xb + dp->xs * col,
297 dp->yb + dp->ys * row,
298 dp->xs - 1, dp->ys - 1,
299 0, 23040);
300 }
301 } else
302 (void) XPutImage(display, window, gc,
303 &logo[bitmap], 0, 0,
304 dp->xb + dp->xs * col, dp->yb + dp->ys * row,
305 icon_width, icon_height);
306 } else { /* TRI */
307 int orient = (col + row) % 2; /* O left 1 right */
308 Bool small = (dp->xs <= 3 || dp->ys <= 3);
309 int ix = 0, iy = 0;
310
311 if (dp->vertical) {
312 dp->shape.triangle[orient][0].x = dp->xb + col * dp->xs;
313 dp->shape.triangle[orient][0].y = dp->yb + row * dp->ys;
314 if (small)
315 dp->shape.triangle[orient][0].x +=
316 ((orient) ? -1 : 1);
317 else
318 dp->shape.triangle[orient][0].x +=
319 (dp->xs / 2 - 1) * ((orient) ? 1 : -1);
320 ix = ((orient) ? -dp->xs / 2 : dp->xs / 2);
321 } else {
322 dp->shape.triangle[orient][0].y = dp->xb + col * dp->xs;
323 dp->shape.triangle[orient][0].x = dp->yb + row * dp->ys;
324 if (small)
325 dp->shape.triangle[orient][0].y +=
326 ((orient) ? -1 : 1);
327 else
328 dp->shape.triangle[orient][0].y +=
329 (dp->xs / 2 - 1) * ((orient) ? 1 : -1);
330 iy = ((orient) ? -dp->xs / 2 : dp->xs / 2);
331 }
332 if (small)
333 XDrawPoint(display, window, gc,
334 dp->shape.triangle[orient][0].x,
335 dp->shape.triangle[orient][0].y);
336 else {
337 if (bitmap == BITMAPS - 1) {
338 XFillPolygon(display, window, gc,
339 dp->shape.triangle[orient], 3,
340 Convex, CoordModePrevious);
341 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
342 XDrawLines(display, window, gc,
343 dp->shape.triangle[orient], 4,
344 CoordModePrevious);
345 } else {
346 if (firstChange) {
347 XSetForeground(display, gc,
348 MI_BLACK_PIXEL(mi));
349 XFillPolygon(display, window, gc,
350 dp->shape.triangle[orient], 3,
351 Convex, CoordModePrevious);
352 XSetForeground(display, gc, colour);
353 }
354 if (dp->vertical) {
355 dp->shape.triangle[orient][0].x += -4 * dp->xs / 5 +
356 ((orient) ? dp->xs / 3 : 3 * dp->xs / 5);
357 dp->shape.triangle[orient][0].y += -dp->ys / 2 + 1;
358 ix = ((orient) ? -dp->xs / 2 : dp->xs / 2);
359 } else {
360 dp->shape.triangle[orient][0].y += -4 * dp->xs / 5 +
361 ((orient) ? dp->xs / 3 : 3 * dp->xs / 5);
362 dp->shape.triangle[orient][0].x += -dp->ys / 2 + 1;
363 iy = ((orient) ? -dp->xs / 2 : dp->xs / 2);
364 }
365 XFillArc(display, window, gc,
366 dp->shape.triangle[orient][0].x + ix,
367 dp->shape.triangle[orient][0].y + iy,
368 dp->ys - 3, dp->ys - 3,
369 0, 23040);
370 }
371 }
372 }
373 }
374
375 static void
addtolist(ModeInfo * mi,int col,int row,int state)376 addtolist(ModeInfo * mi, int col, int row, int state)
377 {
378 dilemmastruct *dp = &dilemmas[MI_SCREEN(mi)];
379 CellList *current;
380
381 current = dp->cellList[state];
382 dp->cellList[state] = (CellList *) malloc(sizeof (CellList));
383 dp->cellList[state]->pt.x = col;
384 dp->cellList[state]->pt.y = row;
385 dp->cellList[state]->next = current;
386 }
387
388 #ifdef DEBUG
389 static void
print_state(ModeInfo * mi,int state)390 print_state(ModeInfo * mi, int state)
391 {
392 dilemmastruct *dp = &dilemmas[MI_SCREEN(mi)];
393 CellList *locallist;
394 int i = 0;
395
396 locallist = dp->cellList[state];
397 (void) printf("state %d\n", state);
398 while (locallist) {
399 (void) printf("%d x %d, y %d\n", i,
400 locallist->pt.x, locallist->pt.y);
401 locallist = locallist->next;
402 i++;
403 }
404 }
405
406 #endif
407
408 static void
free_state(dilemmastruct * dp,int state)409 free_state(dilemmastruct * dp, int state)
410 {
411 CellList *current;
412
413 while (dp->cellList[state]) {
414 current = dp->cellList[state];
415 dp->cellList[state] = dp->cellList[state]->next;
416 free(current);
417 }
418 dp->cellList[state] = (CellList *) NULL;
419 }
420
421
422 static void
free_list(dilemmastruct * dp)423 free_list(dilemmastruct * dp)
424 {
425 int state;
426
427 for (state = 0; state < COLORS; state++)
428 free_state(dp, state);
429 }
430
431 static void
free_dilemma_screen(dilemmastruct * dp)432 free_dilemma_screen(dilemmastruct *dp)
433 {
434 if (dp == NULL) {
435 return;
436 }
437 free_list(dp);
438 if (dp->sn != NULL) {
439 free(dp->sn);
440 dp->sn = (char *) NULL;
441 }
442 if (dp->s != NULL) {
443 free(dp->s);
444 dp->s = (char *) NULL;
445 }
446 if (dp->payoff != NULL) {
447 free(dp->payoff);
448 dp->payoff = (float *) NULL;
449 }
450 dp = NULL;
451 }
452
453 static void
alloc_dilemma(dilemmastruct * dp)454 alloc_dilemma(dilemmastruct *dp)
455 {
456 if ((dp->s = (char *) calloc(dp->npositions, sizeof (char))) == NULL) {
457 free_dilemma_screen(dp);
458 return;
459 }
460 if ((dp->sn = (char *) calloc(dp->npositions, sizeof (char))) == NULL) {
461 free_dilemma_screen(dp);
462 return;
463 }
464 if ((dp->payoff = (float *) calloc(dp->npositions,
465 sizeof (float))) == NULL) {
466 free_dilemma_screen(dp);
467 return;
468 }
469 }
470
471
472 static int
positionOfNeighbor(dilemmastruct * dp,int n,int col,int row)473 positionOfNeighbor(dilemmastruct * dp, int n, int col, int row)
474 {
475 int dir = n * (360 / dp->neighbors);
476
477 if (dp->polygon == 4 || dp->polygon == 6) {
478 switch (dir) {
479 case 0:
480 col = (col + 1 == dp->ncols) ? 0 : col + 1;
481 break;
482 case 45:
483 col = (col + 1 == dp->ncols) ? 0 : col + 1;
484 row = (!row) ? dp->nrows - 1 : row - 1;
485 break;
486 case 60:
487 if (!(row & 1))
488 col = (col + 1 == dp->ncols) ? 0 : col + 1;
489 row = (!row) ? dp->nrows - 1 : row - 1;
490 break;
491 case 90:
492 row = (!row) ? dp->nrows - 1 : row - 1;
493 break;
494 case 120:
495 if (row & 1)
496 col = (!col) ? dp->ncols - 1 : col - 1;
497 row = (!row) ? dp->nrows - 1 : row - 1;
498 break;
499 case 135:
500 col = (!col) ? dp->ncols - 1 : col - 1;
501 row = (!row) ? dp->nrows - 1 : row - 1;
502 break;
503 case 180:
504 col = (!col) ? dp->ncols - 1 : col - 1;
505 break;
506 case 225:
507 col = (!col) ? dp->ncols - 1 : col - 1;
508 row = (row + 1 == dp->nrows) ? 0 : row + 1;
509 break;
510 case 240:
511 if (row & 1)
512 col = (!col) ? dp->ncols - 1 : col - 1;
513 row = (row + 1 == dp->nrows) ? 0 : row + 1;
514 break;
515 case 270:
516 row = (row + 1 == dp->nrows) ? 0 : row + 1;
517 break;
518 case 300:
519 if (!(row & 1))
520 col = (col + 1 == dp->ncols) ? 0 : col + 1;
521 row = (row + 1 == dp->nrows) ? 0 : row + 1;
522 break;
523 case 315:
524 col = (col + 1 == dp->ncols) ? 0 : col + 1;
525 row = (row + 1 == dp->nrows) ? 0 : row + 1;
526 break;
527 default:
528 (void) fprintf(stderr, "wrong direction %d\n", dir);
529 }
530 } else if (dp->polygon == 3) {
531 if ((col + row) & 1) { /* right */
532 switch (dir) {
533 case 0:
534 col = (!col) ? dp->ncols - 1 : col - 1;
535 break;
536 case 30:
537 case 40:
538 col = (!col) ? dp->ncols - 1 : col - 1;
539 row = (row + 1 == dp->nrows) ? 0 : row + 1;
540 break;
541 case 60:
542 col = (!col) ? dp->ncols - 1 : col - 1;
543 if (row + 1 == dp->nrows)
544 row = 1;
545 else if (row + 2 == dp->nrows)
546 row = 0;
547 else
548 row = row + 2;
549 break;
550 case 80:
551 case 90:
552 if (row + 1 == dp->nrows)
553 row = 1;
554 else if (row + 2 == dp->nrows)
555 row = 0;
556 else
557 row = row + 2;
558 break;
559 case 120:
560 row = (row + 1 == dp->nrows) ? 0 : row + 1;
561 break;
562 case 150:
563 case 160:
564 col = (col + 1 == dp->ncols) ? 0 : col + 1;
565 row = (row + 1 == dp->nrows) ? 0 : row + 1;
566 break;
567 case 180:
568 col = (col + 1 == dp->ncols) ? 0 : col + 1;
569 break;
570 case 200:
571 case 210:
572 col = (col + 1 == dp->ncols) ? 0 : col + 1;
573 row = (!row) ? dp->nrows - 1 : row - 1;
574 break;
575 case 240:
576 row = (!row) ? dp->nrows - 1 : row - 1;
577 break;
578 case 270:
579 case 280:
580 if (!row)
581 row = dp->nrows - 2;
582 else if (!(row - 1))
583 row = dp->nrows - 1;
584 else
585 row = row - 2;
586 break;
587 case 300:
588 col = (!col) ? dp->ncols - 1 : col - 1;
589 if (!row)
590 row = dp->nrows - 2;
591 else if (!(row - 1))
592 row = dp->nrows - 1;
593 else
594 row = row - 2;
595 break;
596 case 320:
597 case 330:
598 col = (!col) ? dp->ncols - 1 : col - 1;
599 row = (!row) ? dp->nrows - 1 : row - 1;
600 break;
601 default:
602 (void) fprintf(stderr, "wrong direction %d\n",
603 dir);
604 }
605 } else { /* left */
606 switch (dir) {
607 case 0:
608 col = (col + 1 == dp->ncols) ? 0 : col + 1;
609 break;
610 case 30:
611 case 40:
612 col = (col + 1 == dp->ncols) ? 0 : col + 1;
613 row = (!row) ? dp->nrows - 1 : row - 1;
614 break;
615 case 60:
616 col = (col + 1 == dp->ncols) ? 0 : col + 1;
617 if (!row)
618 row = dp->nrows - 2;
619 else if (row == 1)
620 row = dp->nrows - 1;
621 else
622 row = row - 2;
623 break;
624 case 80:
625 case 90:
626 if (!row)
627 row = dp->nrows - 2;
628 else if (row == 1)
629 row = dp->nrows - 1;
630 else
631 row = row - 2;
632 break;
633 case 120:
634 row = (!row) ? dp->nrows - 1 : row - 1;
635 break;
636 case 150:
637 case 160:
638 col = (!col) ? dp->ncols - 1 : col - 1;
639 row = (!row) ? dp->nrows - 1 : row - 1;
640 break;
641 case 180:
642 col = (!col) ? dp->ncols - 1 : col - 1;
643 break;
644 case 200:
645 case 210:
646 col = (!col) ? dp->ncols - 1 : col - 1;
647 row = (row + 1 == dp->nrows) ? 0 : row + 1;
648 break;
649 case 240:
650 row = (row + 1 == dp->nrows) ? 0 : row + 1;
651 break;
652 case 270:
653 case 280:
654 if (row + 1 == dp->nrows)
655 row = 1;
656 else if (row + 2 == dp->nrows)
657 row = 0;
658 else
659 row = row + 2;
660 break;
661 case 300:
662 col = (col + 1 == dp->ncols) ? 0 : col + 1;
663 if (row + 1 == dp->nrows)
664 row = 1;
665 else if (row + 2 == dp->nrows)
666 row = 0;
667 else
668 row = row + 2;
669 break;
670 case 320:
671 case 330:
672 col = (col + 1 == dp->ncols) ? 0 : col + 1;
673 row = (row + 1 == dp->nrows) ? 0 : row + 1;
674 break;
675 default:
676 (void) fprintf(stderr, "wrong direction %d\n",
677 dir);
678 }
679 }
680 #if 0
681 } else {
682 int orient = ((row & 1) * 2 + col) % 4;
683 switch (orient) { /* up, down, left, right */
684 case 0:
685 switch (dir) {
686 case 0:
687 col++;
688 break;
689 case 51: /* 7 */
690 case 72: /* 5 */
691 col = (col + 2 >= dp->ncols) ? 0 : col + 2;
692 break;
693 case 102: /* 7 corner */
694 col = (col + 3 >= dp->ncols) ? 1 : col + 3;
695 row = (row == 0) ? dp->nrows - 1 : row - 1;
696 break;
697 case 144: /* 5 */
698 case 153: /* 7 */
699 col++;
700 row = (row == 0) ? dp->nrows - 1 : row - 1;
701 break;
702 case 204: /* 7 */
703 case 216: /* 5 */
704 row = (row == 0) ? dp->nrows - 1 : row - 1;
705 break;
706 case 255: /* 7 */
707 col = (col == 0) ? dp->ncols - 1 : col - 1;
708 row = (row == 0) ? dp->nrows - 1 : row - 1;
709 break;
710 case 288: /* 5 */
711 case 306: /* 7 */
712 col = (col == 0) ? dp->ncols - 1 : col - 1;
713 break;
714 default:
715 (void) fprintf(stderr, "wrong direction %d\n",
716 dir);
717 }
718 break;
719 case 1:
720 switch (dir) {
721 case 0:
722 col--;
723 break;
724 case 51: /* 7 */
725 case 72: /* 5 */
726 col = (col == 1) ? dp->ncols - 1 : col - 2;
727 break;
728 case 102: /* 7 */
729 col = (col == 1) ? dp->ncols - 2 : col - 3;
730 row = (row + 1 == dp->nrows) ? 0 : row + 1;
731 break;
732 case 144: /* 5 */
733 case 153: /* 7 */
734 col--;
735 row = (row + 1 == dp->nrows) ? 0 : row + 1;
736 break;
737 case 204: /* 7 */
738 case 216: /* 5 */
739 row = (row + 1 == dp->nrows) ? 0 : row + 1;
740 break;
741 case 255: /* 7 */
742 col = (col + 1 >= dp->ncols) ? 0 : col + 1;
743 row = (row + 1 == dp->nrows) ? 0 : row + 1;
744 break;
745 case 288: /* 5 */
746 case 306: /* 7 */
747 col = (col + 1 >= dp->ncols) ? 0 : col + 1;
748 break;
749 default:
750 (void) fprintf(stderr, "wrong direction %d\n",
751 dir);
752 }
753 break;
754 case 2:
755 switch (dir) {
756 case 0:
757 col = (col + 1 >= dp->ncols) ? 0 : col + 1;
758 break;
759 case 51: /* 7 */
760 case 72: /* 5 */
761 row = (row == 0) ? dp->nrows - 1 : row - 1;
762 col++;
763 break;
764 case 102: /* 7 */
765 col = (col == 0) ? dp->ncols - 1 : col - 1;
766 row = (row == 0) ? dp->nrows - 1 : row - 1;
767 break;
768 case 144: /* 5 */
769 case 153: /* 7 */
770 col = (col == 0) ? dp->ncols - 2 : col - 2;
771 break;
772 case 204: /* 7 */
773 case 216: /* 5 */
774 col = (col == 0) ? dp->ncols - 1 : col - 1;
775 break;
776 case 255: /* 7 */
777 row = (row + 1 == dp->nrows) ? 0 : row + 1;
778 col = (col == 0) ? dp->ncols - 1 : col - 1;
779 break;
780 case 288: /* 5 */
781 case 306: /* 7 */
782 row = (row + 1 == dp->nrows) ? 0 : row + 1;
783 break;
784 default:
785 (void) fprintf(stderr, "wrong direction %d\n",
786 dir);
787 }
788 break;
789 case 3:
790 switch (dir) {
791 case 0:
792 col--;
793 break;
794 case 51: /* 7 */
795 case 72: /* 5 */
796 col = (col == 0) ? dp->ncols - 1 : col - 1;
797 row = (row + 1 == dp->nrows) ? 0 : row + 1;
798 break;
799 case 102: /* 7 */
800 col = (col + 1 >= dp->ncols) ? 0 : col + 1;
801 row = (row + 1 == dp->nrows) ? 0 : row + 1;
802 break;
803 case 144: /* 5 */
804 case 153: /* 7 */
805 col = (col + 2 >= dp->ncols) ? 1 : col + 2;
806 break;
807 case 204: /* 7 */
808 case 216: /* 5 */
809 col = (col + 1 >= dp->ncols) ? 0 : col + 1;
810 break;
811 case 255: /* 7 */
812 col = (col + 1 >= dp->ncols) ? 0 : col + 1;
813 row = (row == 0) ? dp->nrows - 1 : row - 1;
814 break;
815 case 288: /* 5 */
816 case 306: /* 7 */
817 row = (row == 0) ? dp->nrows - 1 : row - 1;
818 break;
819 default:
820 (void) fprintf(stderr, "wrong direction %d\n",
821 dir);
822 }
823 break;
824 default:
825 (void) fprintf(stderr, "wrong orient %d\n",
826 orient);
827 }
828 #endif
829 }
830 return (row * dp->ncols + col);
831 }
832 static void
draw_state(ModeInfo * mi,int state)833 draw_state(ModeInfo * mi, int state)
834 {
835 dilemmastruct *dp = &dilemmas[MI_SCREEN(mi)];
836 CellList *current;
837
838
839 current = dp->cellList[state];
840 while (current) {
841 int col = current->pt.x;
842 int row = current->pt.y;
843 int colrow = col + row * dp->ncols;
844
845 drawcell(mi, col, row,
846 dp->colors[(int) dp->sn[colrow]][(int) dp->s[colrow]],
847 dp->sn[colrow], False);
848 if (dp->s[colrow] && !dp->sn[colrow])
849 dp->defectors--;
850 if (!dp->s[colrow] && dp->sn[colrow])
851 dp->defectors++;
852 dp->s[colrow] = dp->sn[colrow];
853 current = current->next;
854 }
855 free_state(dp, state);
856 XFlush(MI_DISPLAY(mi));
857 }
858
859 ENTRYPOINT void
init_dilemma(ModeInfo * mi)860 init_dilemma(ModeInfo * mi)
861 {
862 int size = MI_SIZE(mi);
863 int i, col, row, colrow, mrow;
864 dilemmastruct *dp;
865
866 MI_INIT(mi, dilemmas);
867 dp = &dilemmas[MI_SCREEN(mi)];
868
869 dp->generation = 0;
870 dp->redrawing = 0;
871 dp->state = 0;
872 free_dilemma_screen(dp);
873
874 if (!dp->initialized) { /* Genesis */
875 icon_width = cooperat_width;
876 icon_height = cooperat_height;
877 dp->initialized = 1;
878 for (i = 0; i < BITMAPS; i++) {
879 logo[i].width = icon_width;
880 logo[i].height = icon_height;
881 logo[i].bytes_per_line = (icon_width + 7) / 8;
882 }
883 }
884 if (MI_IS_FULLRANDOM(mi)) {
885 dp->vertical = (Bool) (LRAND() & 1);
886 } else {
887 dp->vertical = vertical;
888 }
889 dp->width = MI_WIDTH(mi);
890 dp->height = MI_HEIGHT(mi);
891
892 for (i = 0; i < NEIGHBORKINDS; i++) {
893 if (neighbors == plots[i]) {
894 dp->neighbors = neighbors;
895 break;
896 }
897 if (i == NEIGHBORKINDS - 1) {
898 #if 0
899 dp->neighbors = plots[NRAND(NEIGHBORKINDS)];
900 dp->neighbors = (LRAND() & 1) ? 4 : 8;
901 #else
902 dp->neighbors = 8;
903 #endif
904 break;
905 }
906 }
907
908 if (dp->neighbors == 6) {
909 int nccols, ncrows, sides;
910
911 dp->polygon = 6;
912 if (!dp->vertical) {
913 dp->height = MI_WIDTH(mi);
914 dp->width = MI_HEIGHT(mi);
915 }
916 if (dp->width < 2)
917 dp->width = 2;
918 if (dp->height < 4)
919 dp->height = 4;
920 if (size < -MINSIZE)
921 dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
922 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
923 else if (size < MINSIZE) {
924 if (!size)
925 dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
926 else
927 dp->ys = MINSIZE;
928 } else
929 dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
930 MINGRIDSIZE));
931 dp->xs = dp->ys;
932 dp->pixelmode = True;
933 nccols = MAX(dp->width / dp->xs - 2, 2);
934 ncrows = MAX(dp->height / dp->ys - 1, 2);
935 dp->ncols = nccols / 2;
936 dp->nrows = 2 * (ncrows / 4);
937 dp->xb = (dp->width - dp->xs * nccols) / 2 + dp->xs / 2;
938 dp->yb = (dp->height - dp->ys * (ncrows / 2) * 2) / 2 +
939 dp->ys - 2;
940 for (sides = 0; sides < 6; sides++) {
941 if (dp->vertical) {
942 dp->shape.hexagon[sides].x =
943 (dp->xs - 1) * hexagonUnit[sides].x;
944 dp->shape.hexagon[sides].y =
945 ((dp->ys - 1) * hexagonUnit[sides].y /
946 2) * 4 / 3;
947 } else {
948 dp->shape.hexagon[sides].y =
949 (dp->xs - 1) * hexagonUnit[sides].x;
950 dp->shape.hexagon[sides].x =
951 ((dp->ys - 1) * hexagonUnit[sides].y /
952 2) * 4 / 3;
953 }
954 }
955 } else if (dp->neighbors == 4 || dp->neighbors == 8) {
956 dp->polygon = 4;
957 if (dp->width < 2)
958 dp->width = 2;
959 if (dp->height < 2)
960 dp->height = 2;
961 if (size == 0 ||
962 MINGRIDSIZE * size > dp->width || MINGRIDSIZE * size > dp->height) {
963 if (dp->width > MINGRIDSIZE * icon_width &&
964 dp->height > MINGRIDSIZE * icon_height) {
965 dp->pixelmode = False;
966 dp->xs = icon_width;
967 dp->ys = icon_height;
968 } else {
969 dp->pixelmode = True;
970 dp->xs = dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) /
971 MINGRIDSIZE);
972 }
973 } else {
974 dp->pixelmode = True;
975 if (size < -MINSIZE)
976 dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
977 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
978 else if (size < MINSIZE)
979 dp->ys = MINSIZE;
980 else
981 dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
982 MINGRIDSIZE));
983 dp->xs = dp->ys;
984 }
985 dp->ncols = MAX(dp->width / dp->xs, 2);
986 dp->nrows = MAX(dp->height / dp->ys, 2);
987 dp->xb = (dp->width - dp->xs * dp->ncols) / 2;
988 dp->yb = (dp->height - dp->ys * dp->nrows) / 2;
989 } else { /* TRI */
990 int orient;
991
992 dp->polygon = 3;
993 if (!dp->vertical) {
994 dp->height = MI_WIDTH(mi);
995 dp->width = MI_HEIGHT(mi);
996 }
997 if (dp->width < 2)
998 dp->width = 2;
999 if (dp->height < 2)
1000 dp->height = 2;
1001 if (size < -MINSIZE)
1002 dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
1003 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1004 else if (size < MINSIZE) {
1005 if (!size)
1006 dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
1007 else
1008 dp->ys = MINSIZE;
1009 } else
1010 dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
1011 MINGRIDSIZE));
1012 dp->xs = (int) (1.52 * dp->ys);
1013 dp->pixelmode = True;
1014 dp->ncols = (MAX(dp->width / dp->xs - 1, 2) / 2) * 2;
1015 dp->nrows = (MAX(dp->height / dp->ys - 1, 2) / 2) * 2;
1016 dp->xb = (dp->width - dp->xs * dp->ncols) / 2 + dp->xs / 2;
1017 dp->yb = (dp->height - dp->ys * dp->nrows) / 2 + dp->ys / 2;
1018 for (orient = 0; orient < 2; orient++) {
1019 for (i = 0; i < 3; i++) {
1020 if (dp->vertical) {
1021 dp->shape.triangle[orient][i].x =
1022 (dp->xs - 2) * triangleUnit[orient][i].x;
1023 dp->shape.triangle[orient][i].y =
1024 (dp->ys - 2) * triangleUnit[orient][i].y;
1025 } else {
1026 dp->shape.triangle[orient][i].y =
1027 (dp->xs - 2) * triangleUnit[orient][i].x;
1028 dp->shape.triangle[orient][i].x =
1029 (dp->ys - 2) * triangleUnit[orient][i].y;
1030 }
1031 }
1032 }
1033 }
1034
1035 dp->npositions = dp->ncols * dp->nrows;
1036
1037 dp->pm[0][0] = 1, dp->pm[0][1] = 0;
1038 if (bonus < 1.0 || bonus > 4.0)
1039 dp->pm[1][0] = 1.85;
1040 else
1041 dp->pm[1][0] = bonus;
1042 dp->pm[1][1] = 0;
1043
1044 if (MI_NPIXELS(mi) >= COLORS) {
1045
1046 dp->colors[0][0] = MI_PIXEL(mi, BLUE); /* COOPERATING, was cooperating */
1047 dp->colors[0][1] = MI_PIXEL(mi, GREEN); /* COOPERATING, was defecting */
1048 dp->colors[1][0] = MI_PIXEL(mi, YELLOW); /* DEFECTING, was cooperating */
1049 dp->colors[1][1] = MI_PIXEL(mi, RED); /* DEFECTING, was defecting */
1050 } else {
1051 dp->colors[0][0] = MI_WHITE_PIXEL(mi);
1052 dp->colors[0][1] = MI_WHITE_PIXEL(mi);
1053 dp->colors[1][0] = MI_WHITE_PIXEL(mi);
1054 dp->colors[1][1] = MI_WHITE_PIXEL(mi);
1055 }
1056 alloc_dilemma(dp);
1057 if (dp->s == NULL)
1058 return;
1059 MI_CLEARWINDOW(mi);
1060
1061 dp->defectors = MI_COUNT(mi);
1062 if (dp->defectors < -MINDEFECT) {
1063 dp->defectors = NRAND(-dp->defectors - MINDEFECT + 1) + MINDEFECT;
1064 } else if (dp->defectors < MINDEFECT)
1065 dp->defectors = MINDEFECT;
1066 if (dp->defectors > dp->npositions)
1067 dp->defectors = dp->npositions;
1068
1069 for (i = 0; i < dp->defectors; i++) {
1070 do {
1071 colrow = NRAND(dp->npositions);
1072 } while (dp->sn[colrow]);
1073 dp->sn[colrow] = 1;
1074 }
1075 #if 0 /* if p was a float... */
1076 mrow = 0;
1077 for (row = 0; row < dp->nrows; row++) {
1078 for (col = 0; col < dp->ncols; col++) {
1079 dp->sn[col + mrow] = ((float) LRAND() / MAXRAND < dp->p);
1080 }
1081 mrow += dp->ncols;
1082 }
1083 #endif
1084
1085 dp->defectors = 0;
1086
1087 /* Show initial state... real important for debugging */
1088 mrow = 0;
1089 for (row = 0; row < dp->nrows; ++row) {
1090 for (col = 0; col < dp->ncols; ++col) {
1091 addtolist(mi, col, row,
1092 dp->sn[col + mrow] * BITMAPS + dp->s[col + mrow]);
1093 }
1094 mrow += dp->ncols;
1095 }
1096 }
1097
1098 ENTRYPOINT void
draw_dilemma(ModeInfo * mi)1099 draw_dilemma(ModeInfo * mi)
1100 {
1101 int col, row, mrow, colrow, n, i;
1102 dilemmastruct *dp;
1103
1104 if (dilemmas == NULL)
1105 return;
1106 dp = &dilemmas[MI_SCREEN(mi)];
1107 if (dp->s == NULL)
1108 return;
1109
1110 MI_IS_DRAWN(mi) = True;
1111
1112 if (dp->state >= 2 * COLORS) {
1113
1114 for (col = 0; col < dp->ncols; col++) {
1115 for (row = 0; row < dp->nrows; row++) {
1116 colrow = col + row * dp->ncols;
1117 if (conscious)
1118 dp->payoff[colrow] =
1119 dp->pm[(int) dp->s[colrow]][(int) dp->s[colrow]];
1120 else
1121 dp->payoff[colrow] = 0.0;
1122 for (n = 0; n < dp->neighbors; n++)
1123 dp->payoff[colrow] +=
1124 dp->pm[(int) dp->s[colrow]][(int)
1125 dp->s[positionOfNeighbor(dp,
1126 n, col, row)]];
1127
1128 }
1129 }
1130 for (row = 0; row < dp->nrows; row++) {
1131 for (col = 0; col < dp->ncols; col++) {
1132 float hp;
1133 int position;
1134
1135 colrow = col + row * dp->ncols;
1136 hp = dp->payoff[colrow];
1137 dp->sn[colrow] = dp->s[colrow];
1138 for (n = 0; n < dp->neighbors; n++) {
1139 position = positionOfNeighbor(dp, n, col, row);
1140 if (ROUND_FLOAT(dp->payoff[position], 0.001) >
1141 ROUND_FLOAT(hp, 0.001)) {
1142 hp = dp->payoff[position];
1143 dp->sn[colrow] = dp->s[position];
1144 }
1145 }
1146 }
1147 }
1148 mrow = 0;
1149 for (row = 0; row < dp->nrows; row++) {
1150 for (col = 0; col < dp->ncols; col++) {
1151 addtolist(mi, col, row,
1152 dp->sn[col + mrow] * BITMAPS + dp->s[col + mrow]);
1153 }
1154 mrow += dp->ncols;
1155 }
1156
1157 if (++dp->generation > MI_CYCLES(mi) ||
1158 dp->defectors == dp->npositions || dp->defectors == 0)
1159 init_dilemma(mi);
1160 dp->state = 0;
1161 } else {
1162 if (dp->state < COLORS) {
1163 draw_state(mi, dp->state);
1164 }
1165 dp->state++;
1166 }
1167 #if 1
1168 if (dp->redrawing) {
1169 for (i = 0; i < REDRAWSTEP; i++) {
1170 drawcell(mi, dp->redrawpos % dp->ncols, dp->redrawpos / dp->ncols,
1171 dp->colors[(int) dp->sn[dp->redrawpos]][(int) dp->s[dp->redrawpos]],
1172 dp->sn[dp->redrawpos], False);
1173 if (++(dp->redrawpos) >= dp->npositions) {
1174 dp->redrawing = 0;
1175 break;
1176 }
1177 }
1178 }
1179 #endif
1180 }
1181
1182 ENTRYPOINT void
release_dilemma(ModeInfo * mi)1183 release_dilemma(ModeInfo * mi)
1184 {
1185 if (dilemmas != NULL) {
1186 int screen;
1187
1188 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1189 free_dilemma_screen(&dilemmas[screen]);
1190 free(dilemmas);
1191 dilemmas = (dilemmastruct *) NULL;
1192 }
1193 }
1194
1195 #ifndef STANDALONE
1196 ENTRYPOINT void
refresh_dilemma(ModeInfo * mi)1197 refresh_dilemma(ModeInfo * mi)
1198 {
1199 dilemmastruct *dp = &dilemmas[MI_SCREEN(mi)];
1200
1201 dp->redrawing = 1;
1202 dp->redrawpos = 0;
1203 }
1204 #endif
1205
1206 XSCREENSAVER_MODULE ("Dilemma", dilemma)
1207
1208 #endif /* MODE_dilemma */
1209