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