1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* ant3d --- Extension to Langton's generalized turing machine ants */
3
4 #if 0
5 static const char sccsid[] = "@(#)ant3d.c 5.13 2004/07/23 xlockmore";
6
7 #endif
8 /*-
9 * Copyright (c) 1999 by David Bagley.
10 *
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
16 *
17 * This file is provided AS IS with no warranties of any kind. The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof. In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
22 *
23 * Revision History:
24 * 28-Jun-2004: A few more features added, need better "eyes" on leading
25 * cube (instead of a small black face)
26 * 08-Jun-2004: Resurrected code after seeing Heiko Hamann's "Definition
27 * Behavior of Langton's Ant in Three Dimensions", Complex
28 * Systems Volume 14, Issue 3, (2003) pp 264-268
29 * heiko.hamann AT gmx.de
30 * 12-Aug-1999: Coded from life3d.c and ant.c probably will not work but...
31 */
32
33 #ifdef STANDALONE
34 # define MODE_ant3d
35 # define DEFAULTS "*delay: 5000 \n" \
36 "*count: -3 \n" \
37 "*cycles: 10000 \n" \
38 "*ncolors: 200 \n" \
39 "*wireframe: False \n" \
40 "*fullrandom: False \n" \
41 "*verbose: False \n"\
42
43 # define reshape_ant3d 0
44 # define ant3d_handle_event 0
45 # include "xlockmore.h" /* in xscreensaver distribution */
46 #else /* STANDALONE */
47 # include "xlock.h" /* in xlockmore distribution */
48 #endif /* STANDALONE */
49 #define DO_STIPPLE
50 #include "automata.h"
51
52 #ifdef MODE_ant3d
53
54 #define DEF_LABEL "True"
55 #define FONT_HEIGHT 19
56 #define FONT_WIDTH 15
57
58 /*-
59 * neighbors of 0 randomizes it for 6, 8, 12, 14, 18, 20, 26
60 */
61 #define DEF_NEIGHBORS "0" /* choose random value */
62 #define DEF_RULE "A" /* All rules */
63 #define DEF_EYES "False"
64
65 static Bool label;
66 static int neighbors;
67 static char *rule;
68 static Bool eyes;
69
70 static XrmOptionDescRec opts[] =
71 {
72 {(char *) "-label", (char *) ".ant3d.label", XrmoptionNoArg, (caddr_t) "on"},
73 {(char *) "+label", (char *) ".ant3d.label", XrmoptionNoArg, (caddr_t) "off"},
74 {(char *) "-neighbors", (char *) ".ant3d.neighbors", XrmoptionSepArg, (caddr_t) NULL},
75 {(char *) "-rule", (char *) ".ant3d.rule", XrmoptionSepArg, (caddr_t) NULL},
76 {(char *) "-eyes", (char *) ".ant3d.eyes", XrmoptionNoArg, (caddr_t) "on"}
77 ,
78 {(char *) "+eyes", (char *) ".ant3d.eyes", XrmoptionNoArg, (caddr_t) "off"}
79 };
80 static argtype vars[] =
81 {
82 {(void *) & label, (char *) "label", (char *) "Label", (char *) DEF_LABEL, t_Bool},
83 {(void *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int},
84 {(void *) & rule, (char *) "rule", (char *) "Rule", (char *) DEF_RULE, t_String},
85 {(void *) & eyes, (char *) "eyes", (char *) "Eyes", (char *) DEF_EYES, t_Bool}
86 };
87 static OptionStruct desc[] =
88 {
89 {(char *) "-/+label", (char *) "turn on/off rule labeling"},
90 {(char *) "-neighbors num", (char *) "cubes 6, 8, 14, 18, 20, 26, or rhombic dodecahedron 12"},
91 {(char *) "-rule string", (char *) "base 4 string for Turk's Ant"},
92 {(char *) "-/+eyes", (char *) "turn on/off eyes"}
93 };
94
95 ENTRYPOINT ModeSpecOpt ant3d_opts =
96 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
97
98 #ifdef USE_MODULES
99 ModStruct ant3d_description =
100 {"ant3d", "init_ant3d", "draw_ant3d", "release_ant3d",
101 "refresh_ant3d", "init_ant3d", "free_ant3d", &ant3d_opts,
102 5000, -3, 10000, 1, 64, 1.0, "",
103 "Shows 3D ants", 0, NULL};
104
105 #endif
106
107 #define ANT3DBITS(n,w,h)\
108 if ((ap->pixmaps[ap->init_bits]=\
109 XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\
110 free_ant3d_screen(display,ap); return;} else {ap->init_bits++;}
111
112 /* If you change the table you may have to change the following 2 constants */
113 #define STATES 2
114 #define MINANTS 1
115 #define REDRAWSTEP 2000 /* How much tape to draw per cycle */
116
117 /* Don't change these numbers without changing the offset() macro below! */
118 #define MAXSTACKS 64
119 #define MAXROWS 128
120 #define MAXCOLUMNS 128
121 #define BASESIZE ((MAXCOLUMNS*MAXROWS*MAXSTACKS)>>6)
122
123 #define RT_ANGLE 90
124 #define HALFRT_ANGLE 45
125
126 /* Store state of cell in top bit. Reserve low bits for count of living nbrs */
127 #define Set3D(x,y,z,c) SetMem(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)
128 #define Reset3D(x,y,z) SetMem(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,0)
129
130 #define SetList3D(x,y,z,c) if (!SetMem(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)) return False; \
131 if (!AddToList(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)) return False
132 #define InitSetList3D(x,y,z,c) if (!SetMem(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)) return; \
133 if (!AddToList(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)) return
134
135 #define ChangeList3D(i,x,y,z,c) if (!SetMem(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)) return False; \
136 ChangeInList(ap,i,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)
137
138 #define EyeToScreen 72.0 /* distance from eye to screen */
139 #define HalfScreenD 20.0 /* 1/2 the diameter of screen */
140 #define BUCKETSIZE 10
141 #define NBUCKETS ((MAXCOLUMNS+MAXROWS+MAXSTACKS)*BUCKETSIZE)
142 #define Distance(x1,y1,z1,x2,y2,z2) sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2))
143
144 #define IP (M_PI / 180.0)
145 #define NCOLORS 14
146
147 typedef struct {
148 unsigned char color;
149 short turn;
150 unsigned char next;
151 } statestruct;
152
153 typedef struct _antstruct {
154 int col, row, stack;
155 unsigned char color;
156 char visible;
157 short direction; /* Direction facing */
158 short gravity; /* Need to know which way is down */
159 unsigned char state;
160 short dist; /* dist from cell to eye */
161 struct _antstruct *next; /* pointer to next entry on linked list */
162 struct _antstruct *prev;
163 struct _antstruct *priority;
164 } antstruct;
165
166 typedef struct {
167 Bool painted;
168 int neighbors;
169 int ox, oy, oz; /* origin */
170 double vx, vy, vz; /* viewpoint */
171 int generation;
172 int ncols, nrows, nstacks;
173 int memstart;
174 unsigned char *base[BASESIZE];
175 double A, B, C, F;
176 int width, height;
177 unsigned char ncolors, nstates;
178 int n;
179 double azm;
180 double metaAlt, metaAzm, metaDist;
181 antstruct *ants;
182 antstruct **antList;
183 antstruct *ptrhead, *ptrend, eraserhead, eraserend;
184 antstruct *buckethead[NBUCKETS], *bucketend[NBUCKETS];
185 Bool wireframe, eyes;
186 Pixmap dbuf;
187 statestruct machine[NCOLORS * STATES];
188 unsigned char *tape;
189 int init_bits;
190 unsigned long colors[NCOLORS - 1];
191 GC stippledGC;
192 Pixmap pixmaps[NCOLORS - 1];
193 int nInvisible;
194 int labelOffsetX, labelOffsetY;
195 char ruleString[50];
196 } antfarm3dstruct;
197
198 static char plots[] =
199 {12, 26};
200 #define NEIGHBORKINDS ((long) (sizeof plots / sizeof *plots))
201
202 /* Coordinate ant moves */
203 #define NU -1 /* Not used */
204 #define XN 0
205 #define XP 1
206 #define YN 2
207 #define YP 3
208 #define ZN 4
209 #define ZP 5
210 #define XNYN 0 /* Rhombic Dodecahedron */
211 #define XPYN 1
212 #define XNYP 2
213 #define XPYP 3
214 #define YNZN 4
215 #define YPZN 5
216 #define YNZP 6
217 #define YPZP 7
218 #define ZNXN 8
219 #define ZPXN 9
220 #define ZNXP 10
221 #define ZPXP 11
222
223 /* Relative ant moves */
224 #define TRS 0 /* Turn right, then step */
225 #define TLS 1 /* Turn left, then step */
226 #define TUS 2 /* Turn up, then step */
227 #define TDS 3 /* Turn down, then step */
228 #define FS 4 /* Step */
229 #define TBS 5 /* Turn back, then step */
230 /* Uhhh for completeness I guess there are some yaw moves and a 180 TU */
231 #define STR 6 /* Step then turn right */
232 #define STL 7 /* Step then turn left */
233 #define STU 8 /* Step then turn up */
234 #define STD 9 /* Step then turn down */
235 #define SF 10 /* Step */
236 #define STB 11 /* Step then turn back */
237 /* Relative bee moves, leading R for Rhombic */
238 #define RTRS 0 /* Turn right, then step */
239 #define RTLS 1 /* Turn left, then step */
240 /* can also include hard turns but did not yet */
241 #define RTURS 2 /* Turn up-right, then step */
242 #define RTDRS 3 /* Turn down-right, then step */
243 #define RTULS 4 /* Turn up-left, then step */
244 #define RTDLS 5 /* Turn down-left, then step */
245 #define RFS 6 /* Step */
246 #define RTBS 7 /* Turn back, then step */
247 /* Uhhh for completeness I guess there are some yaw moves and a 180 TU */
248 #define RSTR 8 /* Step then turn right */
249 #define RSTL 9 /* Step then turn left */
250 #define RSTUR 10 /* Step then turn up-right */
251 #define RSTDR 11 /* Step then turn down-right */
252 #define RSTUL 12 /* Step then turn up-left */
253 #define RSTDL 13 /* Step then turn down-left */
254 #define RSF 14 /* Step */
255 /* turnDirection, oldGravity, oldDirection */
256 /*gravity XN, traveling along a direction YN, get TRS, now ZP */
257 static int newDirectionMap[4][6][6] = {
258 { /* TRS */
259 {NU, NU, ZP, ZN, YN, YP}, /* oldGravity = XN */
260 {NU, NU, ZN, ZP, YP, YN},
261 {ZN, ZP, NU, NU, XP, XN}, /* oldGravity = YN */
262 {ZP, ZN, NU, NU, XN, XP},
263 {YP, YN, XN, XP, NU, NU}, /* oldGravity = ZN */
264 {YN, YP, XP, XN, NU, NU}
265 },
266 { /* TLS */
267 {NU, NU, ZN, ZP, YP, YN}, /* oldGravity = XN */
268 {NU, NU, ZP, ZN, YN, YP},
269 {ZP, ZN, NU, NU, XN, XP}, /* oldGravity = YN */
270 {ZN, ZP, NU, NU, XP, XN},
271 {YN, YP, XP, XN, NU, NU}, /* oldGravity = ZN */
272 {YP, YN, XN, XP, NU, NU}
273 },
274 { /* TUS */
275 {NU, NU, XP, XP, XP, XP}, /* oldGravity = XN */
276 {NU, NU, XN, XN, XN, XN},
277 {YP, YP, NU, NU, YP, YP}, /* oldGravity = YN */
278 {YN, YN, NU, NU, YN, YN},
279 {ZP, ZP, ZP, ZP, NU, NU}, /* oldGravity = ZN */
280 {ZN, ZN, ZN, ZN, NU, NU}
281 },
282 { /* TDS */
283 {NU, NU, XN, XN, XN, XN}, /* oldGravity = XN */
284 {NU, NU, XP, XP, XP, XP},
285 {YN, YN, NU, NU, YN, YN}, /* oldGravity = YN */
286 {YP, YP, NU, NU, YP, YP},
287 {ZN, ZN, ZN, ZN, NU, NU}, /* oldGravity = ZN */
288 {ZP, ZP, ZP, ZP, NU, NU}
289 }
290 };
291 /* turnDirection, oldGravity, oldDirection */
292 static int newGravityMap[4][6][6] = {
293 { /* TRS */
294 {NU, NU, XN, XN, XN, XN}, /* oldGravity = XN */
295 {NU, NU, XP, XP, XP, XP},
296 {YN, YN, NU, NU, YN, YN}, /* oldGravity = YN */
297 {YP, YP, NU, NU, YP, YP},
298 {ZN, ZN, ZN, ZN, NU, NU}, /* oldGravity = ZN */
299 {ZP, ZP, ZP, ZP, NU, NU}
300 },
301 { /* TLS */
302 {NU, NU, XN, XN, XN, XN}, /* oldGravity = XN */
303 {NU, NU, XP, XP, XP, XP},
304 {YN, YN, NU, NU, YN, YN}, /* oldGravity = YN */
305 {YP, YP, NU, NU, YP, YP},
306 {ZN, ZN, ZN, ZN, NU, NU}, /* oldGravity = ZN */
307 {ZP, ZP, ZP, ZP, NU, NU}
308 },
309 { /* TUS */
310 {NU, NU, YN, YP, ZN, ZP}, /* oldGravity = XN */
311 {NU, NU, YN, YP, ZN, ZP},
312 {XN, XP, NU, NU, ZN, ZP}, /* oldGravity = YN */
313 {XN, XP, NU, NU, ZN, ZP},
314 {XN, XP, YN, YP, NU, NU}, /* oldGravity = ZN */
315 {XN, XP, YN, YP, NU, NU}
316 },
317 { /* TDS */
318 {NU, NU, YP, YN, ZP, ZN}, /* oldGravity = XN */
319 {NU, NU, YP, YN, ZP, ZN},
320 {XP, XN, NU, NU, ZP, ZN}, /* oldGravity = YN */
321 {XP, XN, NU, NU, ZP, ZN},
322 {XP, XN, YP, YN, NU, NU}, /* oldGravity = ZN */
323 {XP, XN, YP, YN, NU, NU}
324 }
325 };
326 /* turnDirection, oldGravity, oldDirection */
327 /* XNYN 0, XPYN 1, XNYP 2, XPYP 3
328 YNZN 4, YPZN 5, YNZP 6, YPZP 7
329 ZNXN 8, ZPXN 9, ZNXP 10,ZPXP 11 */
330 /*gravity XN, traveling along a direction YNZN, get RTRS, now YNZP */
331 static int newRDirectionMap[6][6][4] = {
332 { /* RTRS:YNZN YPZN YNZP YPZP */
333 {YPZN, YPZP, YNZN, YNZP}, /* YZ, oldGravity = XN */
334 {YNZP, YNZN, YPZP, YPZN},
335 {ZPXN, ZPXP, ZNXN, ZNXP}, /* ZX, oldGravity = YN */
336 {ZNXP, ZNXN, ZPXP, ZPXN},
337 {XPYN, XPYP, XNYN, XNYP}, /* XY, oldGravity = ZN */
338 {XNYP, XNYN, XPYP, XPYN}
339 },
340 { /* RTLS */
341 {YNZP, YNZN, YPZP, YPZN}, /* oldGravity = XN */
342 {YPZN, YPZP, YNZN, YNZP},
343 {ZNXP, ZNXN, ZPXP, ZPXN}, /* oldGravity = YN */
344 {ZPXN, ZPXP, ZNXN, ZNXP},
345 {XNYP, XNYN, XPYP, XPYN}, /* oldGravity = ZN */
346 {XPYN, XPYP, XNYN, XNYP}
347 },
348 { /* RTURS */
349 {ZNXN, XNYP, XNYN, ZPXN}, /* oldGravity = XN */
350 {XPYN, ZNXP, ZPXP, XPYP},
351 {XNYN, YNZP, YNZN, XPYN}, /* oldGravity = YN */
352 {YPZN, XNYP, XPYP, YPZP},
353 {YNZN, ZNXP, ZNXN, YPZN}, /* oldGravity = ZN */
354 {ZPXN, YNZP, YPZP, ZPXP}
355 },
356 { /* RTDRS */
357 {ZNXP, XPYP, XPYN, ZPXP}, /* oldGravity = XN */
358 {XNYN, ZNXN, ZPXN, XNYP},
359 {XNYP, YPZP, YPZN, XPYP}, /* oldGravity = YN */
360 {YNZN, XNYN, XPYN, YNZP},
361 {YNZP, ZPXP, ZPXN, YPZP}, /* oldGravity = ZN */
362 {ZNXN, YNZN, YPZN, ZNXP}
363 },
364 { /* RTULS */
365 {XNYN, ZNXN, ZPXN, XNYP}, /* oldGravity = XN */
366 {ZNXP, XPYP, XPYN, ZPXP},
367 {YNZN, XNYN, XPYN, YNZP}, /* oldGravity = YN */
368 {XNYP, YPZP, YPZN, XPYP},
369 {ZNXN, YNZN, YPZN, ZNXP}, /* oldGravity = ZN */
370 {YNZP, ZPXP, ZPXN, YPZP}
371 },
372 { /* RTDLS */
373 {XPYN, ZNXP, ZPXP, XPYP}, /* oldGravity = XN */
374 {ZNXN, XNYP, XNYN, ZPXN},
375 {YPZN, XNYP, XPYP, YPZP}, /* oldGravity = YN */
376 {XNYN, YNZP, YNZN, XPYN},
377 {ZPXN, YNZP, YPZP, ZPXP}, /* oldGravity = ZN */
378 {YNZN, ZNXP, ZNXN, YPZN}
379 }
380 };
381 /* turnDirection, oldGravity, oldDirection */
382 /* XNYN 0, XPYN 1, XNYP 2, XPYP 3
383 YNZN 4, YPZN 5, YNZP 6, YPZP 7
384 ZNXN 8, ZPXN 9, ZNXP 10,ZPXP 11 */
385 static int newRGravityMap[6][6][4] = {
386 { /* RTRS:YNZN YPZN YNZP YPZP */
387 {XN, XN, XN, XN}, /* oldGravity = XN */
388 {XP, XP, XP, XP},
389 {YN, YN, YN, YN}, /* oldGravity = YN */
390 {YP, YP, YP, YP},
391 {ZN, ZN, ZN, ZN}, /* oldGravity = ZN */
392 {ZP, ZP, ZP, ZP}
393 },
394 { /* RTLS */
395 {XN, XN, XN, XN}, /* oldGravity = XN */
396 {XP, XP, XP, XP},
397 {YN, YN, YN, YN}, /* oldGravity = YN */
398 {YP, YP, YP, YP},
399 {ZN, ZN, ZN, ZN}, /* oldGravity = ZN */
400 {ZP, ZP, ZP, ZP}
401 },
402 { /* RTURS */
403 {YP, ZP, ZN, YN}, /* oldGravity = XN */
404 {ZP, YN, YP, ZN},
405 {ZP, XP, XN, ZN}, /* oldGravity = YN */
406 {XP, ZN, ZP, XN},
407 {XP, YP, YN, XN}, /* oldGravity = ZN */
408 {YP, XN, XP, YN}
409 },
410 { /* RTDRS */
411 {YN, ZN, ZP, YP}, /* oldGravity = XN */
412 {ZN, YP, YN, ZP},
413 {ZN, XN, XP, ZP}, /* oldGravity = YN */
414 {XN, ZP, ZN, XP},
415 {XN, YN, YP, XP}, /* oldGravity = ZN */
416 {YN, XP, XN, YP}
417 },
418 { /* RTULS */
419 {ZP, YN, YP, ZN}, /* oldGravity = XN */
420 {YP, ZP, ZN, YN},
421 {XP, ZN, ZP, XN}, /* oldGravity = YN */
422 {ZP, XP, XN, ZN},
423 {YP, XN, XP, YN}, /* oldGravity = ZN */
424 {XP, YP, YN, XN}
425 },
426 { /* RTDLS */
427 {ZN, YP, YN, ZP}, /* oldGravity = XN */
428 {YN, ZN, ZP, YP},
429 {XN, ZP, ZN, XP}, /* oldGravity = YN */
430 {ZN, XN, XP, ZP},
431 {YN, XP, XN, YP}, /* oldGravity = ZN */
432 {XN, YN, YP, XP}
433 }
434 };
435 static antfarm3dstruct *antfarm3ds = NULL;
436
437 static unsigned char tables[][3 * NCOLORS * STATES + 2] =
438 {
439 #if 0
440 /* Generated */
441 { /* 0: RLU */
442 3, 1,
443 1, TRS, 0, 2, TLS, 0, 0, TUS, 0
444 },
445 { /* 1: RUL */
446 3, 1,
447 1, TRS, 0, 2, TUS, 0, 0, TLS, 0
448 },
449 { /* 2: RUD */
450 3, 1,
451 1, TRS, 0, 2, TUS, 0, 0, TDS, 0
452 },
453 { /* 3: RLUU */
454 4, 1,
455 1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TUS, 0
456 },
457 { /* 4: RRLU 32 */
458 4, 1,
459 1, TRS, 0, 2, TRS, 0, 3, TLS, 0, 0, TUS, 0
460 },
461 { /* 5: RRUL ? */
462 4, 1,
463 1, TRS, 0, 2, TRS, 0, 3, TUS, 0, 0, TLS, 0
464 },
465 { /* 6: RRUD 22 */
466 4, 1,
467 1, TRS, 0, 2, TRS, 0, 3, TUS, 0, 0, TDS, 0
468 },
469 { /* 7: RLRU 188 */
470 4, 1,
471 1, TRS, 0, 2, TLS, 0, 3, TRS, 0, 0, TUS, 0
472 },
473 { /* 8: RLLU ? */
474 4, 1,
475 1, TRS, 0, 2, TLS, 0, 3, TLS, 0, 0, TUS, 0
476 },
477 { /* 9: RLUR 46 ! */
478 4, 1,
479 1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TRS, 0
480 },
481 { /* 10: RLUL 32 */
482 4, 1,
483 1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TLS, 0
484 },
485 { /* 11: RLUU 102 */
486 4, 1,
487 1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TUS, 0
488 },
489 { /* 12: RLUD 28 */
490 4, 1,
491 1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TDS, 0
492 },
493 { /* 13: RURL 30 */
494 4, 1,
495 1, TRS, 0, 2, TUS, 0, 3, TRS, 0, 0, TLS, 0
496 },
497 { /* 14: RURD ? */
498 4, 1,
499 1, TRS, 0, 2, TUS, 0, 3, TRS, 0, 0, TDS, 0
500 },
501 { /* 15: RULL 22 */
502 4, 1,
503 1, TRS, 0, 2, TUS, 0, 3, TLS, 0, 0, TLS, 0
504 },
505 { /* 16: RULR 22 */
506 4, 1,
507 1, TRS, 0, 2, TUS, 0, 3, TLS, 0, 0, TRS, 0
508 },
509 { /* 17: RULU 22 */
510 4, 1,
511 1, TRS, 0, 2, TUS, 0, 3, TLS, 0, 0, TUS, 0
512 },
513 { /* 18: RUUL 26 */
514 4, 1,
515 1, TRS, 0, 2, TUS, 0, 3, TUS, 0, 0, TLS, 0
516 },
517 { /* 19: RULD 22 */
518 4, 1,
519 1, TRS, 0, 2, TUS, 0, 3, TLS, 0, 0, TDS, 0
520 },
521 { /* 20: RUUD 22 */
522 4, 1,
523 1, TRS, 0, 2, TUS, 0, 3, TUS, 0, 0, TDS, 0
524 },
525 { /* 21: RUDR 14 */
526 4, 1,
527 1, TRS, 0, 2, TUS, 0, 3, TDS, 0, 0, TRS, 0
528 },
529 { /* 22: RUDL ? */
530 4, 1,
531 1, TRS, 0, 2, TUS, 0, 3, TDS, 0, 0, TLS, 0
532 },
533 { /* 23: RUDU 114 */
534 4, 1,
535 1, TRS, 0, 2, TUS, 0, 3, TDS, 0, 0, TUS, 0
536 },
537 { /* 24: RUDD 40 */
538 4, 1,
539 1, TRS, 0, 2, TUS, 0, 3, TDS, 0, 0, TDS, 0
540 },
541 { /* 25: RRRULL ? */
542 6, 1,
543 1, TRS, 0, 2, TRS, 0, 3, TRS, 0, 4, TUS, 0,
544 5, TLS, 0, 0, TLS, 0
545 },
546 { /* 26: RLRUUUL 25436 */
547 7, 1,
548 1, TRS, 0, 2, TLS, 0, 3, TRS, 0, 4, TUS, 0,
549 5, TUS, 0, 6, TUS, 0, 0, TLS, 0
550 },
551 #endif
552 { /* 27: RRLDDDULRRLLLL * */
553 14, 1,
554 1, TRS, 0, 2, TRS, 0, 3, TLS, 0, 4, TDS, 0,
555 5, TDS, 0, 6, TDS, 0, 7, TUS, 0, 8, TLS, 0,
556 9, TRS, 0, 10, TRS, 0, 11, TLS, 0, 12, TLS, 0,
557 13, TLS, 0, 0, TLS, 0
558 }
559 };
560
561 #define NTABLES (sizeof tables / sizeof tables[0])
562
563 #ifdef gDEBUG
printDir(int dir,Bool omega)564 static char * printDir(int dir, Bool omega)
565 {
566 if (omega) {
567 switch (dir) {
568 case XNYN: return (char *) "XNYN";
569 case XPYN: return (char *) "XPYN";
570 case XNYP: return (char *) "XNYP";
571 case XPYP: return (char *) "XPYP";
572 case YNZN: return (char *) "YNZN";
573 case YPZN: return (char *) "YPZN";
574 case YNZP: return (char *) "YNZP";
575 case YPZP: return (char *) "YPZP";
576 case ZNXN: return (char *) "ZNXN";
577 case ZPXN: return (char *) "ZPXN";
578 case ZNXP: return (char *) "ZNXP";
579 case ZPXP: return (char *) "ZPXP";
580 default: return (char *) "NUNU";
581 }
582 } else {
583 switch (dir) {
584 case XN: return (char *) "XN";
585 case XP: return (char *) "XP";
586 case YN: return (char *) "YN";
587 case YP: return (char *) "YP";
588 case ZN: return (char *) "ZN";
589 case ZP: return (char *) "ZP";
590 default: return (char *) "NU";
591 }
592 }
593 }
594
printTurn(antfarm3dstruct * ap,int dir)595 static char * printTurn(antfarm3dstruct * ap, int dir)
596 {
597 if (ap->neighbors == 12) {
598 switch (dir) {
599 case RTRS: return (char *) "RTRS";
600 case RTLS: return (char *) "RTLS";
601 case RTURS: return (char *) "RTURS";
602 case RTDRS: return (char *) "RTDRS";
603 case RTULS: return (char *) "RTULS";
604 case RTDLS: return (char *) "RTDLS";
605 default: return (char *) "RTXX";
606 }
607 } else {
608 switch (dir) {
609 case TRS: return (char *) "TRS";
610 case TLS: return (char *) "TLS";
611 case TUS: return (char *) "TUS";
612 case TDS: return (char *) "TDS";
613 default: return (char *) "TXX";
614 }
615 }
616 }
617 #endif
618
heading(antfarm3dstruct * ap,short * direction,short * gravity,short turn)619 static void heading(antfarm3dstruct * ap, short * direction, short * gravity,
620 short turn)
621 {
622 short oldDirection = *direction;
623 short oldGravity = *gravity;
624
625 if (ap->neighbors == 12) {
626 if (turn < 8) {
627 if (turn == RTBS) {
628 if (oldDirection & 1)
629 *direction = oldDirection - 1;
630 else
631 *direction = oldDirection + 1;
632 } else if (turn < 6) {
633 *gravity = newRGravityMap
634 [turn][oldGravity][oldDirection % 4];
635 *direction = newRDirectionMap
636 [turn][oldGravity][oldDirection % 4];
637 }
638 }
639 } else {
640 if (turn < 6) {
641 if (turn == TBS) {
642 if (oldDirection & 1)
643 *direction = oldDirection - 1;
644 else
645 *direction = oldDirection + 1;
646 } else if (turn < 4) {
647 *gravity = newGravityMap
648 [turn][oldGravity][oldDirection];
649 *direction = newDirectionMap
650 [turn][oldGravity][oldDirection];
651 }
652 }
653 }
654 if (*gravity == NU)
655 (void) fprintf(stderr, "gravity corruption\n");
656 if (*direction == NU)
657 (void) fprintf(stderr, "direction corruption\n");
658 #ifdef gDEBUG
659 (void) printf(
660 "odirection %s, ogravity %s, turn %s, direction %s, gravity %s\n",
661 printDir(oldDirection, (ap->neighbors == 12)),
662 printDir(oldGravity, False),
663 printTurn(ap, turn),
664 printDir(*direction, (ap->neighbors == 12)),
665 printDir(*gravity, False));
666 #endif
667 }
668
669 static void
positionOfNeighbor(antfarm3dstruct * ap,int dir,int * pcol,int * prow,int * pstack)670 positionOfNeighbor(antfarm3dstruct * ap, int dir,
671 int *pcol, int *prow, int *pstack)
672 {
673 int col = *pcol, row = *prow, stack = *pstack;
674
675 if (ap->neighbors == 12) {
676 switch (dir) {
677 case XNYN:
678 col = (!col) ? ap->ncols - 1 : col - 1;
679 row = (!row) ? ap->nrows - 1 : row - 1;
680 break;
681 case XPYN:
682 col = (col + 1 == ap->ncols) ? 0 : col + 1;
683 row = (!row) ? ap->nrows - 1 : row - 1;
684 break;
685 case XNYP:
686 col = (!col) ? ap->ncols - 1 : col - 1;
687 row = (row + 1 == ap->nrows) ? 0 : row + 1;
688 break;
689 case XPYP:
690 col = (col + 1 == ap->ncols) ? 0 : col + 1;
691 row = (row + 1 == ap->nrows) ? 0 : row + 1;
692 break;
693 case YNZN:
694 row = (!row) ? ap->nrows - 1 : row - 1;
695 stack = (!stack) ? ap->nstacks - 1 : stack - 1;
696 break;
697 case YPZN:
698 row = (row + 1 == ap->nrows) ? 0 : row + 1;
699 stack = (!stack) ? ap->nstacks - 1 : stack - 1;
700 break;
701 case YNZP:
702 row = (!row) ? ap->nrows - 1 : row - 1;
703 stack = (stack + 1 == ap->nstacks) ? 0 : stack + 1;
704 break;
705 case YPZP:
706 row = (row + 1 == ap->nrows) ? 0 : row + 1;
707 stack = (stack + 1 == ap->nstacks) ? 0 : stack + 1;
708 break;
709 case ZNXN:
710 stack = (!stack) ? ap->nstacks - 1 : stack - 1;
711 col = (!col) ? ap->ncols - 1 : col - 1;
712 break;
713 case ZPXN:
714 stack = (stack + 1 == ap->nstacks) ? 0 : stack + 1;
715 col = (!col) ? ap->ncols - 1 : col - 1;
716 break;
717 case ZNXP:
718 stack = (!stack) ? ap->nstacks - 1 : stack - 1;
719 col = (col + 1 == ap->ncols) ? 0 : col + 1;
720 break;
721 case ZPXP:
722 stack = (stack + 1 == ap->nstacks) ? 0 : stack + 1;
723 col = (col + 1 == ap->ncols) ? 0 : col + 1;
724 break;
725 default:
726 (void) fprintf(stderr, "wrong direction %d\n", dir);
727 }
728 } else {
729 switch (dir) {
730 case XN:
731 col = (!col) ? ap->ncols - 1 : col - 1;
732 break;
733 case XP:
734 col = (col + 1 == ap->ncols) ? 0 : col + 1;
735 break;
736 case YN:
737 row = (!row) ? ap->nrows - 1 : row - 1;
738 break;
739 case YP:
740 row = (row + 1 == ap->nrows) ? 0 : row + 1;
741 break;
742 case ZN:
743 stack = (!stack) ? ap->nstacks - 1 : stack - 1;
744 break;
745 case ZP:
746 stack = (stack + 1 == ap->nstacks) ? 0 : stack + 1;
747 break;
748 default:
749 (void) fprintf(stderr, "wrong direction %d\n", dir);
750 }
751 }
752 *pcol = col;
753 *prow = row;
754 *pstack = stack;
755 }
756
757 /*--- list ---*/
758 /* initialise the state of all cells to OFF */
759 static void
Init3D(antfarm3dstruct * ap)760 Init3D(antfarm3dstruct * ap)
761 {
762 ap->ptrhead = ap->ptrend = NULL;
763 ap->eraserhead.next = &ap->eraserend;
764 ap->eraserend.prev = &ap->eraserhead;
765 }
766
767 /*-
768 * Function that adds the cell (assumed live) at (x,y,z) onto the search
769 * list so that it is scanned in future generations
770 */
771 static Bool
AddToList(antfarm3dstruct * ap,unsigned int x,unsigned int y,unsigned int z,unsigned int c)772 AddToList(antfarm3dstruct * ap,
773 unsigned int x, unsigned int y, unsigned int z, unsigned int c)
774 {
775 antstruct *tmp;
776
777 if ((tmp = (antstruct *) malloc(sizeof (antstruct))) == NULL)
778 return False;
779 tmp->col = x;
780 tmp->row = y;
781 tmp->stack = z;
782 tmp->color = c;
783 if (ap->ptrhead == NULL) {
784 ap->ptrhead = ap->ptrend = tmp;
785 tmp->prev = NULL;
786 } else {
787 ap->ptrend->next = tmp;
788 tmp->prev = ap->ptrend;
789 ap->ptrend = tmp;
790 }
791 ap->ptrend->next = NULL;
792 return True;
793 }
794
795 static void
ChangeInList(antfarm3dstruct * ap,int i,unsigned int x,unsigned int y,unsigned int z,unsigned int c)796 ChangeInList(antfarm3dstruct * ap, int i,
797 unsigned int x, unsigned int y, unsigned int z, unsigned int c)
798 {
799 antstruct *ant = ap->antList[i];
800 ant->col = x;
801 ant->row = y;
802 ant->stack = z;
803 ant->color = c;
804 }
805
806 static void
AddToEraseList(antfarm3dstruct * ap,antstruct * cell)807 AddToEraseList(antfarm3dstruct * ap, antstruct * cell)
808 {
809 cell->next = &ap->eraserend;
810 cell->prev = ap->eraserend.prev;
811 ap->eraserend.prev->next = cell;
812 ap->eraserend.prev = cell;
813 }
814
815 static void
DelFromList(antfarm3dstruct * ap,antstruct * cell)816 DelFromList(antfarm3dstruct * ap, antstruct * cell)
817 {
818 if (cell != ap->ptrhead) {
819 cell->prev->next = cell->next;
820 } else {
821 ap->ptrhead = cell->next;
822 if (ap->ptrhead != NULL)
823 ap->ptrhead->prev = NULL;
824 }
825
826 if (cell != ap->ptrend) {
827 cell->next->prev = cell->prev;
828 } else {
829 ap->ptrend = cell->prev;
830 if (ap->ptrend != NULL)
831 ap->ptrend->next = NULL;
832 }
833 }
834
835 static void
EraseFromList(antfarm3dstruct * ap,antstruct * cell)836 EraseFromList(antfarm3dstruct * ap, antstruct * cell)
837 {
838 DelFromList(ap, cell);
839 AddToEraseList(ap, cell);
840 }
841
842 static void
DelFromEraseList(antstruct * cell)843 DelFromEraseList(antstruct * cell)
844 {
845 cell->next->prev = cell->prev;
846 cell->prev->next = cell->next;
847 free(cell);
848 }
849
850 /*--- memory ---*/
851 /*-
852 * Simulate a large array by dynamically allocating 4x4x4 size cells when
853 * needed.
854 */
855 static void
MemInit(antfarm3dstruct * ap)856 MemInit(antfarm3dstruct * ap)
857 {
858 int i;
859
860 for (i = 0; i < BASESIZE; ++i) {
861 if (ap->base[i] != NULL) {
862 free(ap->base[i]);
863 ap->base[i] = (unsigned char *) NULL;
864 }
865 }
866 ap->memstart = 0;
867 }
868
869 #define BASE_OFFSET(x,y,z,b,o) \
870 b = ((x & 0x7c) << 7) + ((y & 0x7c) << 2) + ((z & 0x7c) >> 2); \
871 o = (x & 3) + ((y & 3) << 2) + ((z & 3) << 4); \
872 if (ap->base[b] == NULL) {\
873 if ((ap->base[b] = (unsigned char *) calloc(64, sizeof (unsigned char))) == NULL) {return False;}}
874
875 #if 0
876 static Bool
877 GetMem(antfarm3dstruct * ap, unsigned int x, unsigned int y, unsigned int z,
878 int *m)
879 {
880 int b, o;
881
882 if (ap->memstart) {
883 MemInit(ap);
884 }
885 BASE_OFFSET(x, y, z, b, o);
886 *m = ap->base[b][o];
887 return True;
888 }
889 #endif
890
891 static Bool
SetMem(antfarm3dstruct * ap,unsigned int x,unsigned int y,unsigned int z,unsigned int val)892 SetMem(antfarm3dstruct * ap,
893 unsigned int x, unsigned int y, unsigned int z, unsigned int val)
894 {
895 int b, o;
896
897 if (ap->memstart) {
898 MemInit(ap);
899 }
900 BASE_OFFSET(x, y, z, b, o);
901 ap->base[b][o] = val;
902 return True;
903 }
904
905 #if 0
906 static Bool
907 ChangeMem(antfarm3dstruct * ap,
908 unsigned int x, unsigned int y, unsigned int z,
909 unsigned int val)
910 {
911 int b, o;
912
913 if (ap->memstart) {
914 MemInit(ap);
915 }
916 BASE_OFFSET(x, y, z, b, o);
917 ap->base[b][o] += val;
918 return True;
919 }
920 #endif
921
922 static void
End3D(antfarm3dstruct * ap)923 End3D(antfarm3dstruct * ap)
924 {
925 antstruct *ptr;
926
927 while (ap->ptrhead != NULL) {
928 /* Reset3D(ap->ptrhead->col, ap->ptrhead->row,
929 ap->ptrhead->stack); */
930 EraseFromList(ap, ap->ptrhead);
931 }
932 ptr = ap->eraserhead.next;
933 while (ptr != &ap->eraserend) {
934 DelFromEraseList(ptr);
935 ptr = ap->eraserhead.next;
936 }
937 MemInit(ap);
938 }
939
940 #if 0
941 /* This does not seem to be needed */
942 static void
943 condenseList(antfarm3dstruct * ap) {
944 antstruct *ptr1 = ap->ptrhead;
945 antstruct *ptr2 = ap->ptrhead;
946 antstruct *tmp = NULL;
947 while (ptr2->next != NULL) {
948 ptr2 = ptr2->next;
949 while (ptr1 != ptr2) {
950 if (ptr1->col == ptr2->col &&
951 ptr1->row == ptr2->row &&
952 ptr1->stack == ptr2->stack) {
953 int found = 0;
954 int i;
955
956 for (i = 0; i < ap->n; i++) {
957 if (ap->antList[i] == ptr1) {
958 found = 1;
959 break;
960 }
961 }
962 if (found == 0)
963 tmp = ptr1;
964 }
965 ptr1 = ptr1->next;
966 if (tmp != NULL) {
967 DelFromList(ap, tmp);
968 free(tmp);
969 tmp = NULL;
970 }
971 }
972 }
973 }
974 #endif
975
976 #ifndef BLACK_CELLS
977 static void
eraseEmpty(antfarm3dstruct * ap)978 eraseEmpty (antfarm3dstruct * ap) {
979 antstruct *ptr1 = ap->ptrhead;
980 antstruct *ptr2 = ap->ptrhead;
981 antstruct *tmp = NULL;
982 int col, row, stack;
983 while (ptr1->next != NULL) {
984 if (ptr1->color == 0) {
985 int found = 0;
986 int i;
987
988 for (i = 0; i < ap->n; i++) {
989 if (ap->antList[i] == ptr1) {
990 found = 1;
991 break;
992 }
993 }
994 if (found == 0)
995 tmp = ptr1;
996 }
997 col = ptr1->col;
998 row = ptr1->row;
999 stack = ptr1->stack;
1000 ptr1 = ptr1->next;
1001 if (tmp != NULL) {
1002 DelFromList(ap, tmp);
1003 free(tmp);
1004 tmp = NULL;
1005 /* may have to delete all in that position */
1006 ptr2 = ap->ptrhead;
1007 while (ptr1 != ptr2) {
1008 if (ptr2->col == col &&
1009 ptr2->row == row &&
1010 ptr2->stack == stack) {
1011 int found = 0;
1012 int i;
1013
1014 for (i = 0; i < ap->n; i++) {
1015 if (ap->antList[i] == ptr2) {
1016 found = 1;
1017 break;
1018 }
1019 }
1020 if (found == 0)
1021 tmp = ptr2;
1022 }
1023 ptr2 = ptr2->next;
1024 if (tmp != NULL) {
1025 DelFromList(ap, tmp);
1026 free(tmp);
1027 tmp = NULL;
1028 }
1029 }
1030 }
1031 }
1032 }
1033 #endif
1034
1035 static Bool
RunAnt3D(antfarm3dstruct * ap)1036 RunAnt3D(antfarm3dstruct * ap)
1037 {
1038 antstruct *anant;
1039 statestruct *status;
1040 int i, state_pos, tape_pos;
1041 unsigned char color;
1042
1043 if (ap->ants == NULL)
1044 return False;
1045
1046 ap->painted = True;
1047 for (i = 0; i < ap->n; i++) {
1048 anant = &ap->ants[i];
1049 tape_pos = anant->col + anant->row * ap->ncols +
1050 anant->stack * ap->nrows * ap->ncols;
1051 color = ap->tape[tape_pos]; /* read tape */
1052 state_pos = color + anant->state * ap->ncolors;
1053 status = &(ap->machine[state_pos]);
1054 #ifdef gDEBUG
1055 (void) printf("status: color %d, turn %s, state %d, colors %d\n",
1056 status->color, printTurn(ap, status->turn),
1057 anant->state, ap->ncolors);
1058 #endif
1059 ChangeList3D(i, anant->col, anant->row, anant->stack,
1060 status->color);
1061 ap->tape[tape_pos] = status->color; /* write on tape */
1062 #ifdef gDEBUG
1063 (void) printf("gen %d: ", ap->generation);
1064 #endif
1065 heading(ap, &(anant->direction), &(anant->gravity), status->turn);
1066 /* Find direction of Bees or Ants. */
1067 /* Translate relative direction to actual direction */
1068 anant->state = status->next;
1069
1070 /* Allow step first then turn */
1071 #ifdef gDEBUG
1072 (void) printf("state %d, col %d, row %d, stack %d",
1073 anant->state, anant->col, anant->row, anant->stack);
1074 #endif
1075 positionOfNeighbor(ap, anant->direction,
1076 &(anant->col), &(anant->row), &(anant->stack));
1077 SetList3D(anant->col, anant->row, anant->stack,
1078 NCOLORS);
1079 ap->antList[i] = ap->ptrend;
1080 }
1081 /*condenseList(ap);*/
1082 #ifndef BLACK_CELLS
1083 eraseEmpty(ap);
1084 #endif
1085 return True;
1086 }
1087
1088 #if 0
1089 static int
1090 CountCells3D(antfarm3dstruct * ap)
1091 {
1092 antstruct *ptr;
1093 int count = 0;
1094
1095 ptr = ap->ptrhead;
1096 while (ptr != NULL) {
1097 ++count;
1098 ptr = ptr->next;
1099 }
1100 return count;
1101 }
1102
1103 void
1104 DisplayList(antfarm3dstruct * ap)
1105 {
1106 antstruct *ptr;
1107 int count = 0;
1108
1109 ptr = ap->ptrhead;
1110 while (ptr != NULL) {
1111 (void) printf("(%x)=[%d,%d,%d] ", (int) ptr,
1112 ptr->x, ptr->y, ptr->z);
1113 ptr = ptr->next;
1114 ++count;
1115 }
1116 (void) printf("Living cells = %d\n", count);
1117 }
1118
1119 #endif
1120
1121 static void
getTable(ModeInfo * mi,int i)1122 getTable(ModeInfo * mi, int i)
1123 {
1124 antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1125 int j, total;
1126 unsigned char *patptr;
1127 statestruct *status;
1128
1129 patptr = &tables[i][0];
1130 ap->ncolors = *patptr++;
1131 ap->nstates = *patptr++;
1132 total = ap->ncolors * ap->nstates;
1133 if (MI_IS_VERBOSE(mi))
1134 (void) fprintf(stdout,
1135 "ants %d, table number %d, colors %d, states %d\n",
1136 ap->n, i, ap->ncolors, ap->nstates);
1137 if (label)
1138 (void) sprintf(ap->ruleString, "%d table number %d", ap->n, i);
1139 for (j = 0; j < total; j++) {
1140 status = &(ap->machine[j]);
1141 status->color = *patptr++;
1142 status->turn = *patptr++;
1143 status->next = *patptr++;
1144 #ifdef DEBUG
1145 (void) printf("Status: color %d, turn %d, colors %d\n",
1146 status->color, status->turn, ap->ncolors);
1147 #endif
1148 }
1149 }
1150
1151 static void
getTurk(ModeInfo * mi,int logClass,int number)1152 getTurk(ModeInfo * mi, int logClass, int number)
1153 {
1154 antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1155 int power4, j, total;
1156 char rule[NCOLORS * STATES + 1];
1157
1158 #ifdef DEBUG
1159 (void) printf("logClass %d, number %d\n", logClass, number);
1160 #endif
1161 power4 = 1 << ((logClass - 1) << 1);
1162 ap->ncolors = logClass;
1163 ap->nstates = 1;
1164 total = ap->ncolors * ap->nstates;
1165 for (j = 0; j < total; j++) {
1166 ap->machine[j].color = (j + 1) % total;
1167 ap->machine[j].turn = ((power4 * 3) & number) / power4;
1168 rule[j] = ap->machine[j].turn + '0';
1169 ap->machine[j].next = 0;
1170 power4 >>= 2;
1171 }
1172 rule[total] = '\0';
1173 if (MI_IS_VERBOSE(mi))
1174 (void) fprintf(stdout,
1175 "ants %d, Turk's number 0x%x (0%s)B4, colors %d\n",
1176 ap->n, number, rule, ap->ncolors);
1177 if (label)
1178 (void) sprintf(ap->ruleString, "%d Turk's number 0x%x",
1179 ap->n, number);
1180 }
1181
1182 static void
parseRule(ModeInfo * mi)1183 parseRule(ModeInfo * mi)
1184 {
1185 antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1186
1187 if (rule) {
1188 int n = 0, l, number = 0, logClass = 0, power4;
1189 int bucket[4];
1190
1191 bucket[0] = bucket[1] = bucket[2] = bucket[3] = 0;
1192 while (rule[n]) {
1193 if (rule[n] == 'T' || rule[n] == 't') {
1194 n++;
1195 while (rule[n]) {
1196 number = number * 10 +
1197 (int) (rule[n] - '0');
1198 n++;
1199 }
1200 getTable(mi, number);
1201 return;
1202 }
1203 if (rule[n] == 'A' || rule[n] == 'a') {
1204 if (!NRAND(2 * NUMSTIPPLES)) {
1205 getTable(mi, (int) (NRAND(NTABLES)));
1206 return;
1207 } else {
1208 int mask = 3, shiftNumber, j;
1209
1210 logClass = (int) (NRAND(NUMSTIPPLES - 4)) + 4;
1211 /* <logClass = 4;> has 4 quadranary digits */
1212 power4 = 1 << (2 * (logClass - 1));
1213 do {
1214 bucket[0] = bucket[1] = bucket[2] = bucket[3] = 0;
1215 number = NRAND(power4 - 1) + power4 *
1216 ((ap->neighbors == 12) ? 1 : (NRAND(3) + 1));
1217 /* leading 2 or 3 just cause boring spirals */
1218 #ifdef DEBUG
1219 (void) printf("number 0x%x, power4 0x%x, logClass %d\n",
1220 number, power4, logClass);
1221 #endif
1222 /* Want to make sure 3 of 4 quadranary digits are here */
1223 shiftNumber = number;
1224 for (j = 0; j < logClass; j++) {
1225 bucket[mask & shiftNumber]++;
1226 shiftNumber = shiftNumber >> 2;
1227 }
1228 #ifdef DEBUG
1229 (void) printf("Buckets: %d %d %d %d\n",
1230 bucket[0], bucket[1], bucket[2], bucket[3]);
1231 #endif
1232 } while ((!bucket[0] && !bucket[1]) || (!bucket[0] && !bucket[2]) ||
1233 (!bucket[0] && !bucket[3]) || (!bucket[1] && !bucket[2]) ||
1234 (!bucket[1] && !bucket[3]) || (!bucket[2] && !bucket[3]));
1235
1236 getTurk(mi, logClass, number);
1237 return;
1238 }
1239 } else {
1240 l = rule[n] - '0';
1241 if (l >= 0 && l <= 3) {
1242 number = (number << 2) + l;
1243 if (logClass > 0 || l != 0)
1244 logClass++;
1245 bucket[l]++;
1246 }
1247 }
1248 n++;
1249 }
1250 #ifdef DEBUG
1251 (void) printf("Buckets: %d %d %d %d\n",
1252 bucket[0], bucket[1], bucket[2], bucket[3]);
1253 #endif
1254 if ((!bucket[0] && !bucket[1]) || (!bucket[0] && !bucket[2]) ||
1255 (!bucket[0] && !bucket[3]) || (!bucket[1] && !bucket[2]) ||
1256 (!bucket[1] && !bucket[3]) || (!bucket[2] && !bucket[3])) {
1257 if (ap->neighbors == 12) {
1258 switch (NRAND(5)) {
1259 case 0: getTurk(mi, 3, 0x12);
1260 break;
1261 case 1: getTurk(mi, 3, 0x13);
1262 break;
1263 case 2: getTurk(mi, 3, 0x18);
1264 break;
1265 case 3: getTurk(mi, 3, 0x1b);
1266 break;
1267 default: getTurk(mi, 4, 0x47);
1268 break;
1269 }
1270 } else {
1271 switch (NRAND(7)) {
1272 case 0: getTurk(mi, 3, 0x12);
1273 break;
1274 case 1: getTurk(mi, 3, 0x13);
1275 break;
1276 case 2: getTurk(mi, 3, 0x18);
1277 break;
1278 case 3: getTurk(mi, 3, 0x1b);
1279 break;
1280 case 4: getTurk(mi, 3, 0x21);
1281 break;
1282 case 5: getTurk(mi, 3, 0x27);
1283 break;
1284 default: getTurk(mi, 3, 0x2d);
1285 break;
1286 }
1287 }
1288 } else {
1289 getTurk(mi, logClass, number);
1290 }
1291 }
1292 }
1293
1294 static void
NewViewpoint(antfarm3dstruct * ap,double x,double y,double z)1295 NewViewpoint(antfarm3dstruct * ap, double x, double y, double z)
1296 {
1297 double k, l, d1, d2;
1298
1299 k = x * x + y * y;
1300 l = sqrt(k + z * z);
1301 k = sqrt(k);
1302 d1 = (EyeToScreen / HalfScreenD);
1303 d2 = EyeToScreen / (HalfScreenD * ap->height / ap->width);
1304 ap->A = d1 * l * (ap->width / 2) / k;
1305 ap->B = l * l;
1306 ap->C = d2 * (ap->height / 2) / k;
1307 ap->F = k * k;
1308 }
1309
1310
1311 static void
lissajous(antfarm3dstruct * ap)1312 lissajous(antfarm3dstruct * ap)
1313 {
1314 double alt, azm, dist;
1315
1316 alt = 44.0 * sin(ap->metaAlt * IP) + 45.0;
1317 ap->metaAlt += 1.123;
1318 if (ap->metaAlt >= 360.0)
1319 ap->metaAlt -= 360.0;
1320 if (ap->metaAlt < 0.0)
1321 ap->metaAlt += 360.0;
1322 azm = 44.0 * sin(ap->metaAzm * IP) + 45.0;
1323 ap->metaAzm += 0.987;
1324 if (ap->metaAzm >= 360.0)
1325 ap->metaAzm -= 360.0;
1326 if (ap->metaAzm < 0.0)
1327 ap->metaAzm += 360.0;
1328 dist = 10.0 * sin(ap->metaDist * IP) + 50.0;
1329 ap->metaDist += 1.0;
1330 if (ap->metaDist >= 360.0)
1331 ap->metaDist -= 360.0;
1332 if (ap->metaDist < 0.0)
1333 ap->metaDist += 360.0;
1334 #if 0
1335 if (alt >= 90.0)
1336 alt = 90.0;
1337 else if (alt < -90.0)
1338 alt = -90.0;
1339 #endif
1340 ap->azm = azm;
1341 #ifdef FDEBUG
1342 (void) printf("dist %g, alt %g, azm %g\n", dist, alt, azm);
1343 #endif
1344 ap->vx = (sin(azm * IP) * cos(alt * IP) * dist);
1345 ap->vy = (cos(azm * IP) * cos(alt * IP) * dist);
1346 ap->vz = (sin(alt * IP) * dist);
1347 NewViewpoint(ap, ap->vx, ap->vy, ap->vz);
1348 }
1349
1350 static void
NewPoint(antfarm3dstruct * ap,double x,double y,double z,register XPoint * pts)1351 NewPoint(antfarm3dstruct * ap, double x, double y, double z,
1352 register XPoint * pts)
1353 {
1354 double p1, E;
1355
1356 p1 = x * ap->vx + y * ap->vy;
1357 E = ap->B - p1 - z * ap->vz;
1358 pts->x = (int) (ap->width / 2 -
1359 ap->A * (ap->vx * y - ap->vy * x) / E);
1360 pts->y = (int) (ap->height / 2 -
1361 ap->C * (z * ap->F - ap->vz * p1) / E);
1362 }
1363
1364
1365 /* Chain together all cells that are at the same distance.
1366 * These cannot mutually overlap. */
1367 static void
SortList(antfarm3dstruct * ap)1368 SortList(antfarm3dstruct * ap)
1369 {
1370 short dist;
1371 double d, col, row, stack, rsize;
1372 int i, r;
1373 XPoint point;
1374 antstruct *ptr;
1375
1376 for (i = 0; i < NBUCKETS; ++i)
1377 ap->buckethead[i] = ap->bucketend[i] = NULL;
1378
1379 /* Calculate distances and re-arrange pointers to chain off buckets */
1380 ptr = ap->ptrhead;
1381 while (ptr != NULL) {
1382
1383 col = (double) ptr->col - ap->ox;
1384 row = (double) ptr->row - ap->oy;
1385 stack = (double) ptr->stack - ap->oz;
1386 d = Distance(ap->vx, ap->vy, ap->vz, col, row, stack);
1387 if (ap->vx * (ap->vx - col) + ap->vy * (ap->vy - row) +
1388 ap->vz * (ap->vz - stack) > 0 && d > 1.5)
1389 ptr->visible = 1;
1390 else
1391 ptr->visible = 0;
1392
1393 ptr->dist = (short) d;
1394 dist = (short) (d * BUCKETSIZE);
1395 if (dist > NBUCKETS - 1)
1396 dist = NBUCKETS - 1;
1397
1398 if (ap->buckethead[dist] == NULL) {
1399 ap->buckethead[dist] = ap->bucketend[dist] = ptr;
1400 ptr->priority = NULL;
1401 } else {
1402 ap->bucketend[dist]->priority = ptr;
1403 ap->bucketend[dist] = ptr;
1404 ap->bucketend[dist]->priority = NULL;
1405 }
1406 ptr = ptr->next;
1407 }
1408
1409 /* Check for invisibility */
1410 rsize = 0.47 * ap->width / ((double) HalfScreenD * 2);
1411 i = (int) ap->azm;
1412 if (i < 0)
1413 i = -i;
1414 i = i % RT_ANGLE;
1415 if (i > HALFRT_ANGLE)
1416 i = RT_ANGLE - i;
1417 rsize /= cos(i * IP);
1418
1419 for (i = 0; i < NBUCKETS; ++i)
1420 if (ap->buckethead[i] != NULL) {
1421 ptr = ap->buckethead[i];
1422 while (ptr != NULL) {
1423 if (ptr->visible) {
1424 col = (double) ptr->col - ap->ox;
1425 row = (double) ptr->row - ap->oy;
1426 stack = (double) ptr->stack - ap->oz;
1427 NewPoint(ap, col, row, stack, &point);
1428
1429 r = (int) (rsize *
1430 (double) EyeToScreen /
1431 (double) ptr->dist);
1432 if (point.x + r < 0 ||
1433 point.y + r < 0 ||
1434 point.x - r >= ap->width ||
1435 point.y - r >= ap->height) {
1436 ap->nInvisible++;
1437 } else if (ap->nInvisible) {
1438 ap->nInvisible = 0;
1439 }
1440 }
1441 ptr = ptr->priority;
1442 }
1443 }
1444 }
1445
1446 static void
DrawEyes(ModeInfo * mi,int color,XPoint * pts,int p1,int p2,int p3,int p4)1447 DrawEyes(ModeInfo * mi, int color, XPoint * pts,
1448 int p1, int p2, int p3, int p4)
1449 {
1450 Display *display = MI_DISPLAY(mi);
1451 GC gc;
1452 antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1453 XPoint facepts[5];
1454 XPoint av;
1455
1456 av.x = (pts[p1].x + pts[p2].x + pts[p3].x + pts[p4].x) / 4;
1457 av.y = (pts[p1].y + pts[p2].y + pts[p3].y + pts[p4].y) / 4;
1458 facepts[0] = pts[p1];
1459 facepts[1] = pts[p2];
1460 facepts[2] = pts[p3];
1461 facepts[3] = pts[p4];
1462 facepts[4] = pts[p1];
1463 facepts[0].x = (av.x + facepts[0].x) / 2;
1464 facepts[0].y = (av.y + facepts[0].y) / 2;
1465 facepts[1].x = (av.x + facepts[1].x) / 2;
1466 facepts[1].y = (av.y + facepts[1].y) / 2;
1467 facepts[2].x = (av.x + facepts[2].x) / 2;
1468 facepts[2].y = (av.y + facepts[2].y) / 2;
1469 facepts[3].x = (av.x + facepts[3].x) / 2;
1470 facepts[3].y = (av.y + facepts[3].y) / 2;
1471 facepts[4].x = (av.x + facepts[4].x) / 2;
1472 facepts[4].y = (av.y + facepts[4].y) / 2;
1473
1474 if (color == NCOLORS) {
1475 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
1476 gc = MI_GC(mi);
1477 } else if (!color) {
1478 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
1479 gc = MI_GC(mi);
1480 } else if (MI_NPIXELS(mi) > 2) {
1481 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
1482 MI_PIXEL(mi, ap->colors[color - 1]));
1483 gc = MI_GC(mi);
1484 } else {
1485 XGCValues gcv;
1486
1487 gcv.stipple = ap->pixmaps[(color - 1) % NUMSTIPPLES];
1488 gcv.foreground = MI_WHITE_PIXEL(mi);
1489 gcv.background = MI_BLACK_PIXEL(mi);
1490 XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
1491 GCStipple | GCForeground | GCBackground, &gcv);
1492 gc = ap->stippledGC;
1493 }
1494 if (!ap->wireframe)
1495 XFillPolygon(display, (Drawable) ap->dbuf, gc, facepts, 4,
1496 Convex, CoordModeOrigin);
1497 gc = MI_GC(mi);
1498 if (!ap->wireframe) {
1499 if (color == NCOLORS) {
1500 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
1501 } else {
1502 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
1503 }
1504 }
1505 XDrawLines(display, (Drawable) ap->dbuf, gc, facepts, 5,
1506 CoordModeOrigin);
1507 }
1508
1509 static void
drawQuad(ModeInfo * mi,int dir,int color,antstruct * cell,XPoint * pts,int p1,int p2,int p3,int p4)1510 drawQuad(ModeInfo * mi, int dir, int color, antstruct * cell, XPoint * pts,
1511 int p1, int p2, int p3, int p4)
1512 {
1513 Display *display = MI_DISPLAY(mi);
1514 GC gc;
1515 antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1516 XPoint facepts[5];
1517
1518 facepts[0] = pts[p1];
1519 facepts[1] = pts[p2];
1520 facepts[2] = pts[p3];
1521 facepts[3] = pts[p4];
1522 facepts[4] = pts[p1];
1523
1524 if (color == NCOLORS) {
1525 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
1526 gc = MI_GC(mi);
1527 } else if (!color) {
1528 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
1529 gc = MI_GC(mi);
1530 } else if (MI_NPIXELS(mi) > 2) {
1531 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
1532 MI_PIXEL(mi, ap->colors[color - 1]));
1533 gc = MI_GC(mi);
1534 } else {
1535 XGCValues gcv;
1536
1537 gcv.stipple = ap->pixmaps[(color - 1) % NUMSTIPPLES];
1538 gcv.foreground = MI_WHITE_PIXEL(mi);
1539 gcv.background = MI_BLACK_PIXEL(mi);
1540 XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
1541 GCStipple | GCForeground | GCBackground, &gcv);
1542 gc = ap->stippledGC;
1543 }
1544 if (!ap->wireframe)
1545 XFillPolygon(display, (Drawable) ap->dbuf, gc, facepts, 4,
1546 Convex, CoordModeOrigin);
1547 gc = MI_GC(mi);
1548 if (!ap->wireframe) {
1549 if (color == NCOLORS) {
1550 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
1551 } else {
1552 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
1553 }
1554 }
1555 XDrawLines(display, (Drawable) ap->dbuf, gc, facepts, 5, CoordModeOrigin);
1556 if (!ap->wireframe && ap->eyes && color == NCOLORS && dir >= 0) {
1557 antstruct *anant;
1558 int i;
1559
1560 for (i = 0; i < ap->n; i++) {
1561 anant = &ap->ants[i];
1562 if (anant->col == cell->col &&
1563 anant->row == cell->row &&
1564 anant->stack == cell->stack) {
1565 #if 0
1566 (void) printf("%d: direction %d, gravity %d\n",
1567 i, anant->direction, anant->gravity);
1568 #endif
1569 /* TODO: use gravity to position better eyes */
1570 if (anant->direction == dir)
1571 DrawEyes(mi, 0, pts, p1, p2, p3, p4);
1572 }
1573 }
1574 }
1575 }
1576
1577 #define LEN 0.45
1578 #define LEN2 0.9
1579
1580 static int
DrawCube(ModeInfo * mi,antstruct * cell)1581 DrawCube(ModeInfo * mi, antstruct * cell)
1582 {
1583 antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1584 XPoint pts[8]; /* screen coords for point */
1585 int i = 0, out = 0;
1586 unsigned int mask;
1587 double x, y, z;
1588 double dx, dy, dz;
1589 int color = cell->color;
1590
1591 x = (double) cell->col - ap->ox;
1592 y = (double) cell->row - ap->oy;
1593 z = (double) cell->stack - ap->oz;
1594 for (dz = z - LEN; dz <= z + LEN2; dz += LEN2)
1595 for (dy = y - LEN; dy <= y + LEN2; dy += LEN2)
1596 for (dx = x - LEN; dx <= x + LEN2; dx += LEN2) {
1597 NewPoint(ap, dx, dy, dz, &pts[i]);
1598 if (pts[i].x < 0 ||
1599 pts[i].x >= ap->width ||
1600 pts[i].y < 0 ||
1601 pts[i].y >= ap->height)
1602 ++out;
1603 ++i;
1604 }
1605 if (out == 8)
1606 return (0);
1607
1608 if (cell->visible)
1609 mask = 0xFFFF;
1610 else
1611 mask = 0x0;
1612
1613 /* Only draw those faces that are visible */
1614 dx = ap->vx - x;
1615 dy = ap->vy - y;
1616 dz = ap->vz - z;
1617 /*
1618 6----7
1619 / /|
1620 / / |
1621 2----3 |
1622 | 4 | 5
1623 | | /
1624 0____1/
1625 */
1626 if (ap->wireframe) {
1627 if (dz <= LEN)
1628 drawQuad(mi, -1, (int) (color & mask), cell, pts, 4, 5, 7, 6);
1629 else if (dz >= -LEN)
1630 drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 1, 3, 2);
1631 if (dx <= LEN)
1632 drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 3, 7, 5);
1633 else if (dx >= -LEN)
1634 drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 2, 6, 4);
1635 if (dy <= LEN)
1636 drawQuad(mi, -1, (int) (color & mask), cell, pts, 2, 3, 7, 6);
1637 else if (dy >= -LEN)
1638 drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 1, 5, 4);
1639 }
1640 if (dz > LEN)
1641 drawQuad(mi, ZP, (int) (color & mask), cell, pts, 4, 5, 7, 6);
1642 else if (dz < -LEN)
1643 drawQuad(mi, ZN, (int) (color & mask), cell, pts, 0, 1, 3, 2);
1644 if (dx > LEN)
1645 drawQuad(mi, XP, (int) (color & mask), cell, pts, 1, 3, 7, 5);
1646 else if (dx < -LEN)
1647 drawQuad(mi, XN, (int) (color & mask), cell, pts, 0, 2, 6, 4);
1648 if (dy > LEN)
1649 drawQuad(mi, YP, (int) (color & mask), cell, pts, 2, 3, 7, 6);
1650 else if (dy < -LEN)
1651 drawQuad(mi, YN, (int) (color & mask), cell, pts, 0, 1, 5, 4);
1652 return (1);
1653 }
1654
1655 static int
DrawRhombicDodecahedron(ModeInfo * mi,antstruct * cell)1656 DrawRhombicDodecahedron(ModeInfo * mi, antstruct * cell)
1657 {
1658 antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1659 XPoint pts[14]; /* screen coords for point */
1660 int i, out = 0, da, db, sortx, sorty, sortz; unsigned int mask;
1661 double x, y, z;
1662 double dx, dy, dz;
1663 int color;
1664
1665 x = (double) cell->col - ap->ox;
1666 y = (double) cell->row - ap->oy;
1667 z = (double) cell->stack - ap->oz;
1668 color = cell->color;
1669 i = 3;
1670 for (dx = x + LEN; dx >= x - LEN2; dx -= LEN2)
1671 for (dy = y + LEN; dy >= y - LEN2; dy -= LEN2)
1672 for (dz = z + LEN; dz >= z - LEN2; dz -= LEN2) {
1673 NewPoint(ap, dx, dy, dz, &pts[i]);
1674 if (pts[i].x < 0 ||
1675 pts[i].x >= ap->width ||
1676 pts[i].y < 0 ||
1677 pts[i].y >= ap->height)
1678 ++out;
1679 ++i;
1680 }
1681 for (da = 0; da < 2; da++) {
1682 if (da == 1) {
1683 i = 0;
1684 } else
1685 i = 11; /* 3 + 8 */
1686 for (db = 0; db < 3; db++) {
1687 if (db == 0) {
1688 dx = ((da == 0) ? -LEN2 : LEN2) + x;
1689 dy = y;
1690 dz = z;
1691 } else if (db == 1) {
1692 dy = ((da == 0) ? -LEN2 : LEN2) + y;
1693 dz = z;
1694 dx = x;
1695 } else {
1696 dz = ((da == 0) ? -LEN2 : LEN2) + z;
1697 dx = x;
1698 dy = y;
1699 }
1700 NewPoint(ap, dx, dy, dz, &pts[i]);
1701 if (pts[i].x < 0 ||
1702 pts[i].x >= ap->width ||
1703 pts[i].y < 0 ||
1704 pts[i].y >= ap->height)
1705 ++out;
1706 ++i;
1707 }
1708 }
1709 if (out == 14)
1710 return (0);
1711
1712 if (cell->visible)
1713 mask = 0xFFFF;
1714 else
1715 mask = 0x0;
1716
1717 /* Only draw those faces that are visible */
1718 dx = ap->vx - x;
1719 dy = ap->vy - y;
1720 dz = ap->vz - z;
1721 /* back points looking through front
1722 8 1 4
1723 7 3
1724 11 2 0
1725 9 5
1726 10 12 6
1727 ---------
1728 front points
1729 7 1 3
1730 8 4
1731 11 13 0
1732 10 6
1733 9 12 5
1734 */
1735 if (ap->wireframe) {
1736 if (dx <= LEN) {
1737 drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1738 drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1739 drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1740 drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1741 } else if (dx >= -LEN) {
1742 drawQuad(mi, -1, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1743 drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1744 drawQuad(mi, -1, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1745 drawQuad(mi, -1, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1746 }
1747 if (dy <= LEN) {
1748 drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1749 drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1750 drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1751 drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1752 } else if (dy >= -LEN) {
1753 drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1754 drawQuad(mi, -1, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1755 drawQuad(mi, -1, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1756 drawQuad(mi, -1, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1757 }
1758 if (dz <= LEN) {
1759 drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1760 drawQuad(mi, -1, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1761 drawQuad(mi, -1, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1762 drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1763 } else if (dz >= -LEN) {
1764 drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1765 drawQuad(mi, -1, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1766 drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1767 drawQuad(mi, -1, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1768 }
1769 }
1770 sortx = sorty = sortz = 0;
1771 if (ABS(dz - LEN) > ABS(dy - LEN))
1772 sortz++;
1773 if (ABS(dz - LEN) > ABS(dx - LEN))
1774 sortz++;
1775 if (ABS(dy - LEN) > ABS(dx - LEN))
1776 sorty++;
1777 if (ABS(dy - LEN) > ABS(dz - LEN))
1778 sorty++;
1779 if (ABS(dx - LEN) > ABS(dz - LEN))
1780 sortx++;
1781 if (ABS(dx - LEN) > ABS(dy - LEN))
1782 sortx++;
1783 for (i = 0; i < 3; i++) {
1784 if (sortx == i) {
1785 if (dx > LEN) {
1786 if (sortz > sorty) {
1787 if (dz < 0)
1788 drawQuad(mi, ZPXP, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1789 else
1790 drawQuad(mi, ZNXP, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1791 drawQuad(mi, XPYN, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1792 drawQuad(mi, XPYP, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1793 if (dz < 0)
1794 drawQuad(mi, ZNXP, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1795 else
1796 drawQuad(mi, ZPXP, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1797 } else {
1798 if (dy < 0)
1799 drawQuad(mi, XPYP, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1800 else
1801 drawQuad(mi, XPYN, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1802 drawQuad(mi, ZNXP, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1803 drawQuad(mi, ZPXP, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1804 if (dy < 0)
1805 drawQuad(mi, XPYN, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1806 else
1807 drawQuad(mi, XPYP, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1808 }
1809 } else if (dx < -LEN) {
1810 if (sortz > sorty) {
1811 if (dz < 0)
1812 drawQuad(mi, ZPXN, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1813 else
1814 drawQuad(mi, ZNXN, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1815 drawQuad(mi, XNYN, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1816 drawQuad(mi, XNYP, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1817 if (dz < 0)
1818 drawQuad(mi, ZNXN, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1819 else
1820 drawQuad(mi, ZPXN, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1821 } else {
1822 if (dy < 0)
1823 drawQuad(mi, XNYP, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1824 else
1825 drawQuad(mi, XNYN, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1826 drawQuad(mi, ZNXN, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1827 drawQuad(mi, ZPXN, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1828 if (dy < 0)
1829 drawQuad(mi, XNYN, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1830 else
1831 drawQuad(mi, XNYP, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1832 }
1833 }
1834 }
1835 if (sorty == i) {
1836 if (dy > LEN) {
1837 if (sortx > sortz) {
1838 if (dx < 0)
1839 drawQuad(mi, XPYP, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1840 else
1841 drawQuad(mi, XNYP, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1842 drawQuad(mi, YPZN, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1843 drawQuad(mi, YPZP, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1844 if (dx < 0)
1845 drawQuad(mi, XNYP, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1846 else
1847 drawQuad(mi, XPYP, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1848 } else {
1849 if (dz < 0)
1850 drawQuad(mi, YPZP, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1851 else
1852 drawQuad(mi, YPZN, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1853 drawQuad(mi, XNYP, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1854 drawQuad(mi, XPYP, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1855 if (dz < 0)
1856 drawQuad(mi, YPZN, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1857 else
1858 drawQuad(mi, YPZP, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1859 }
1860 } else if (dy < -LEN) {
1861 if (sortx > sortz) {
1862 if (dx < 0)
1863 drawQuad(mi, XPYN, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1864 else
1865 drawQuad(mi, XNYN, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1866 drawQuad(mi, YNZP, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1867 drawQuad(mi, YNZN, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1868 if (dx < 0)
1869 drawQuad(mi, XNYN, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1870 else
1871 drawQuad(mi, XPYN, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1872 } else {
1873 if (dz < 0)
1874 drawQuad(mi, YNZP, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1875 else
1876 drawQuad(mi, YNZN, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1877 drawQuad(mi, XNYN, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1878 drawQuad(mi, XPYN, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1879 if (dz < 0)
1880 drawQuad(mi, YNZN, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1881 else
1882 drawQuad(mi, YNZP, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1883 }
1884 }
1885 }
1886 if (sortz == i) {
1887 if (dz > LEN) {
1888 if (sorty > sortx) {
1889 if (dy < 0)
1890 drawQuad(mi, YPZP, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1891 else
1892 drawQuad(mi, YNZP, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1893 drawQuad(mi, ZPXP, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1894 drawQuad(mi, ZPXN, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1895 if (dy < 0)
1896 drawQuad(mi, YNZP, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1897 else
1898 drawQuad(mi, YPZP, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1899 } else {
1900 if (dx < 0)
1901 drawQuad(mi, ZPXP, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1902 else
1903 drawQuad(mi, ZPXN, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1904 drawQuad(mi, YNZP, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1905 drawQuad(mi, YPZP, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1906 if (dx < 0)
1907 drawQuad(mi, ZPXN, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1908 else
1909 drawQuad(mi, ZPXP, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1910 }
1911 } else if (dz < -LEN) {
1912 if (sorty > sortx) {
1913 if (dy < 0)
1914 drawQuad(mi, YPZN, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1915 else
1916 drawQuad(mi, YNZN, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1917 drawQuad(mi, ZNXN, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1918 drawQuad(mi, ZNXP, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1919 if (dy < 0)
1920 drawQuad(mi, YNZN, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1921 else
1922 drawQuad(mi, YPZN, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1923 } else {
1924 if (dx < 0)
1925 drawQuad(mi, ZNXP, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1926 else
1927 drawQuad(mi, ZNXN, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1928 drawQuad(mi, YNZN, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1929 drawQuad(mi, YPZN, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1930 if (dx < 0)
1931 drawQuad(mi, ZNXN, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1932 else
1933 drawQuad(mi, ZNXP, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1934 }
1935 }
1936 }
1937 }
1938 return (1);
1939 }
1940
1941 static void
DrawScreen(ModeInfo * mi)1942 DrawScreen(ModeInfo * mi)
1943 {
1944 antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1945 Display *display = MI_DISPLAY(mi);
1946 GC gc = MI_GC(mi);
1947 antstruct *ptr;
1948 antstruct *eraserptr;
1949 int i;
1950
1951 SortList(ap);
1952
1953 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
1954 XFillRectangle(display, (Drawable) ap->dbuf, gc, 0, 0,
1955 ap->width, ap->height);
1956
1957 /* Erase dead cubes */
1958 eraserptr = ap->eraserhead.next;
1959 while (eraserptr != &ap->eraserend) {
1960 eraserptr->visible = 0;
1961 if (ap->neighbors == 12)
1962 (void) DrawRhombicDodecahedron(mi, eraserptr);
1963 else
1964 (void) DrawCube(mi, eraserptr);
1965 DelFromEraseList(eraserptr);
1966 eraserptr = ap->eraserhead.next;
1967 }
1968
1969 /* draw furthest cubes first */
1970 for (i = NBUCKETS - 1; i >= 0; --i) {
1971 ptr = ap->buckethead[i];
1972 while (ptr != NULL) {
1973 if (ap->neighbors == 12)
1974 (void) DrawRhombicDodecahedron(mi, ptr);
1975 else
1976 /*if (ptr->visible) */
1977 /* v += */ (void) DrawCube(mi, ptr);
1978 ptr = ptr->priority;
1979 /* ++count; */
1980 }
1981 }
1982 if (label) {
1983 int size = MAX(MIN(MI_WIDTH(mi), MI_HEIGHT(mi)) - 1, 1);
1984
1985 if (size >= 10 * FONT_WIDTH) {
1986 /* hard code these to corners */
1987 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
1988 /*XDrawString(display, ap->dbuf, gc,
1989 16 + ap->labelOffsetX,
1990 16 + ap->labelOffsetY + FONT_HEIGHT,
1991 ap->ruleString, strlen(ap->ruleString)); */
1992 XDrawString(display, (Drawable) ap->dbuf, gc,
1993 16 + ap->labelOffsetX, MI_HEIGHT(mi) - 16 -
1994 ap->labelOffsetY - FONT_HEIGHT / 2,
1995 ap->ruleString, strlen(ap->ruleString));
1996 }
1997 }
1998 XFlush(display);
1999 XCopyArea(display, (Drawable) ap->dbuf, MI_WINDOW(mi), gc,
2000 0, 0, ap->width, ap->height, 0, 0);
2001 #if 0
2002 {
2003 int count = 0, v = 0;
2004
2005
2006 (void) printf("Pop=%-4d Viewpoint (%3d,%3d,%3d) Origin (%3d,%3d,%3d) Mode %dx%d\
2007 (%d,%d) %d\n",
2008 count, (int) (ap->vx + ap->ox), (int) (ap->vy + ap->oy),
2009 (int) (ap->vz + ap->oz), (int) ap->ox, (int) ap->oy, (int) ap->oz,
2010 ap->width, ap->height, ap->alt, ap->azm, v);
2011 }
2012 #endif
2013 }
2014
2015 static void
free_ant3d_screen(Display * display,antfarm3dstruct * ap)2016 free_ant3d_screen(Display *display, antfarm3dstruct *ap)
2017 {
2018 int shade;
2019
2020 if (ap == NULL) {
2021 return;
2022 }
2023 if (ap->eraserhead.next != NULL) {
2024 End3D(ap);
2025 }
2026 if (ap->stippledGC != None) {
2027 XFreeGC(display, ap->stippledGC);
2028 ap->stippledGC = None;
2029 }
2030 for (shade = 0; shade < ap->init_bits; shade++) {
2031 XFreePixmap(display, ap->pixmaps[shade]);
2032 }
2033 ap->init_bits = 0;
2034 if (ap->dbuf != None) {
2035 XFreePixmap(display, ap->dbuf);
2036 ap->dbuf = None;
2037 }
2038 if (ap->tape != NULL) {
2039 free(ap->tape);
2040 ap->tape = (unsigned char *) NULL;
2041 }
2042 if (ap->antList != NULL) {
2043 free(ap->antList);
2044 ap->antList = (antstruct **) NULL;
2045 }
2046 if (ap->ants != NULL) {
2047 free(ap->ants);
2048 ap->ants = (antstruct *) NULL;
2049 }
2050 ap = NULL;
2051 }
2052
2053 ENTRYPOINT void
free_ant3d(ModeInfo * mi)2054 free_ant3d(ModeInfo * mi)
2055 {
2056 free_ant3d_screen(MI_DISPLAY(mi), &antfarm3ds[MI_SCREEN(mi)]);
2057 }
2058
2059 ENTRYPOINT void
init_ant3d(ModeInfo * mi)2060 init_ant3d(ModeInfo * mi)
2061 {
2062 Display *display = MI_DISPLAY(mi);
2063 Window window = MI_WINDOW(mi);
2064 antfarm3dstruct *ap;
2065 int i;
2066
2067 MI_INIT(mi, antfarm3ds);
2068 ap = &antfarm3ds[MI_SCREEN(mi)];
2069
2070 ap->nInvisible = 0;
2071 #ifdef DO_STIPPLE
2072 if (MI_NPIXELS(mi) <= 2) {
2073 if (ap->stippledGC == None) {
2074 XGCValues gcv;
2075
2076 gcv.fill_style = FillOpaqueStippled;
2077 if ((ap->stippledGC = XCreateGC(display, window,
2078 GCFillStyle, &gcv)) == None) {
2079 free_ant3d_screen(display, ap);
2080 return;
2081 }
2082 }
2083 if (ap->init_bits == 0) {
2084 for (i = 1; i < NUMSTIPPLES; i++) {
2085 ANT3DBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
2086 }
2087 }
2088 }
2089 #endif /* DO_STIPPLE */
2090 ap->generation = 0;
2091 ap->n = MI_COUNT(mi);
2092 if (ap->n < -MINANTS) {
2093 /* if ap->n is random ... the size can change */
2094 if (ap->ants != NULL) {
2095 free(ap->ants);
2096 ap->ants = NULL;
2097 }
2098 /*ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS;*/
2099 /* skew so that 1 is more likely */
2100 ap->n = -ap->n - (int) (sqrt(NRAND(ap->n *ap->n - 1))) - 1 +
2101 MINANTS;
2102 } else if (ap->n < MINANTS)
2103 ap->n = MINANTS;
2104
2105 for (i = 0; i < NEIGHBORKINDS; i++) {
2106 if (neighbors == plots[i]) {
2107 ap->neighbors = plots[i];
2108 break;
2109 }
2110 if (i == NEIGHBORKINDS - 1) {
2111 ap->neighbors = plots[NRAND(NEIGHBORKINDS)];
2112 break;
2113 }
2114 }
2115
2116 if (!ap->eraserhead.next) {
2117 ap->metaDist = (double) NRAND(360);
2118 ap->metaAlt = (double) NRAND(360);
2119 ap->metaAzm = (double) NRAND(360);
2120 ap->ncols = MAXCOLUMNS;
2121 ap->nrows = MAXROWS;
2122 ap->nstacks = MAXSTACKS;
2123 ap->ox = ap->ncols / 2;
2124 ap->oy = ap->nrows / 2;
2125 ap->oz = ap->nstacks / 2;
2126
2127 Init3D(ap);
2128 } else {
2129 End3D(ap);
2130 }
2131 ap->labelOffsetX = NRAND(8);
2132 ap->labelOffsetY = NRAND(8);
2133 parseRule(mi);
2134 if (MI_NPIXELS(mi) > 2) {
2135 int offset = NRAND(MI_NPIXELS(mi));
2136
2137 for (i = 0; i < (int) ap->ncolors - 1; i++) {
2138 ap->colors[i] = (unsigned char) ((offset +
2139 (i * MI_NPIXELS(mi) /
2140 (int) (ap->ncolors - 1))) % MI_NPIXELS(mi));
2141 }
2142 }
2143 if (ap->tape != NULL)
2144 free(ap->tape);
2145 if ((ap->tape = (unsigned char *) calloc(
2146 ap->ncols * ap->nrows * ap->nstacks,
2147 sizeof (unsigned char))) == NULL) {
2148 free_ant3d_screen(display, ap);
2149 return;
2150 }
2151 ap->width = MI_WIDTH(mi);
2152 ap->height = MI_HEIGHT(mi);
2153 ap->memstart = 1;
2154 /*ap->tablesMade = 0; */
2155
2156 if (MI_IS_FULLRANDOM(mi)) {
2157 ap->wireframe = (NRAND(8) == 0);
2158 } else {
2159 ap->wireframe = MI_IS_WIREFRAME(mi);
2160 }
2161
2162 MI_CLEARWINDOW(mi);
2163 ap->painted = False;
2164
2165 lissajous(ap);
2166 if (ap->ants == NULL) {
2167 if ((ap->ants = (antstruct *) malloc(ap->n *
2168 sizeof (antstruct))) == NULL) {
2169 free_ant3d_screen(display, ap);
2170 return;
2171 }
2172 }
2173 if (ap->antList == NULL) {
2174 if ((ap->antList = (antstruct **) malloc(ap->n *
2175 sizeof (antstruct *))) == NULL) {
2176 free_ant3d_screen(display, ap);
2177 return;
2178 }
2179 }
2180
2181 for (i = 0; i < ap->n; i++) {
2182 antstruct *anant = &ap->ants[i];
2183 anant->col = ap->ncols / 2;
2184 anant->row = ap->nrows / 2;
2185 anant->stack = ap->nstacks / 2;
2186 anant->direction = NRAND((ap->neighbors == 12) ? 12 : 6);
2187 anant->gravity = NRAND(6);
2188 if (ap->neighbors == 12) {
2189 if (anant->direction / 4 == 0) {
2190 anant->gravity = NRAND(2) + ZN;
2191 } else if (anant->direction / 4 == 1) {
2192 anant->gravity = NRAND(2) + XN;
2193 } else {
2194 anant->gravity = NRAND(2) + YN;
2195 }
2196 } else {
2197 while ((anant->gravity / 2) % 3 ==
2198 (anant->direction / 2) % 3)
2199 anant->gravity = NRAND(6);
2200 }
2201 anant->state = 0;
2202 InitSetList3D(anant->col, anant->row, anant->stack,
2203 NCOLORS);
2204 ap->antList[i] = ap->ptrend;
2205 }
2206 if (ap->dbuf != None) {
2207 XFreePixmap(display, ap->dbuf);
2208 ap->dbuf = None;
2209 }
2210 if ((ap->dbuf = XCreatePixmap(display, window,
2211 ap->width, ap->height, MI_DEPTH(mi))) == None) {
2212 free_ant3d_screen(display, ap);
2213 return;
2214 }
2215 if (MI_IS_FULLRANDOM(mi)) {
2216 ap->eyes = (Bool) (LRAND() & 1);
2217 } else {
2218 ap->eyes = eyes;
2219 }
2220 DrawScreen(mi);
2221 }
2222
2223 ENTRYPOINT void
draw_ant3d(ModeInfo * mi)2224 draw_ant3d(ModeInfo * mi)
2225 {
2226 antfarm3dstruct *ap;
2227
2228 if (antfarm3ds == NULL)
2229 return;
2230 ap = &antfarm3ds[MI_SCREEN(mi)];
2231 if (ap->eraserhead.next == NULL)
2232 return;
2233
2234 if (!RunAnt3D(ap)) {
2235 if (ap->eraserhead.next != NULL)
2236 End3D(ap);
2237 return;
2238 }
2239 lissajous(ap);
2240 DrawScreen(mi);
2241 MI_IS_DRAWN(mi) = True;
2242
2243 if (++ap->generation > MI_CYCLES(mi) / ap->n || ap->nInvisible > 32) {
2244 /*CountCells3D(ap) == 0) */
2245 init_ant3d(mi);
2246 } else
2247 ap->painted = True;
2248 }
2249
2250 ENTRYPOINT void
release_ant3d(ModeInfo * mi)2251 release_ant3d(ModeInfo * mi)
2252 {
2253 if (antfarm3ds != NULL) {
2254 int screen;
2255
2256 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
2257 free_ant3d_screen(MI_DISPLAY(mi), &antfarm3ds[screen]);
2258 free(antfarm3ds);
2259 antfarm3ds = (antfarm3dstruct *) NULL;
2260 }
2261 }
2262
2263 #ifndef STANDALONE
2264 ENTRYPOINT void
refresh_ant3d(ModeInfo * mi)2265 refresh_ant3d(ModeInfo * mi)
2266 {
2267 antfarm3dstruct *ap;
2268
2269 if (antfarm3ds == NULL)
2270 return;
2271 ap = &antfarm3ds[MI_SCREEN(mi)];
2272
2273 if (ap->painted) {
2274 MI_CLEARWINDOW(mi);
2275 }
2276 }
2277 #endif
2278
2279 XSCREENSAVER_MODULE ("Ant3d", ant3d)
2280
2281 #endif /* MODE_ant3d */
2282