1 | /* -*- Mode: C; tab-width: 4 -*- */ |
---|
2 | /*- |
---|
3 | * ant --- Chris Langton's generalized turing machine ants (also known |
---|
4 | * as Greg Turk's turmites) whose tape is the screen |
---|
5 | */ |
---|
6 | |
---|
7 | #if 0 |
---|
8 | static const char sccsid[] = "@(#)ant.c 5.00 2000/11/01 xlockmore"; |
---|
9 | #endif |
---|
10 | |
---|
11 | /*- |
---|
12 | * Copyright (c) 1995 by David Bagley. |
---|
13 | * |
---|
14 | * Permission to use, copy, modify, and distribute this software and its |
---|
15 | * documentation for any purpose and without fee is hereby granted, |
---|
16 | * provided that the above copyright notice appear in all copies and that |
---|
17 | * both that copyright notice and this permission notice appear in |
---|
18 | * supporting documentation. |
---|
19 | * |
---|
20 | * This file is provided AS IS with no warranties of any kind. The author |
---|
21 | * shall have no liability with respect to the infringement of copyrights, |
---|
22 | * trade secrets or any patents by this file or any part thereof. In no |
---|
23 | * event will the author be liable for any lost revenue or profits or |
---|
24 | * other special, indirect and consequential damages. |
---|
25 | * |
---|
26 | * Revision History: |
---|
27 | * 01-Nov-2000: Allocation checks |
---|
28 | * 10-May-1997: Compatible with xscreensaver |
---|
29 | * 16-Apr-1997: -neighbors 3 and 8 added |
---|
30 | * 01-Jan-1997: Updated ant.c to handle more kinds of ants. Thanks to |
---|
31 | * J Austin David <Austin.David@tlogic.com>. Check it out in |
---|
32 | * java at http://havoc.gtf.gatech.edu/austin He thought up the |
---|
33 | * new Ladder ant. |
---|
34 | * 04-Apr-1996: -neighbors 6 runtime-time option added for hexagonal ants |
---|
35 | * (bees), coded from an idea of Jim Propp's in Science News, |
---|
36 | * Oct 28, 1995 VOL. 148 page 287 |
---|
37 | * 20-Sep-1995: Memory leak in ant fixed. Now random colors. |
---|
38 | * 05-Sep-1995: Coded from A.K. Dewdney's "Computer Recreations", Scientific |
---|
39 | * American Magazine" Sep 1989 pp 180-183, Mar 1990 p 121 |
---|
40 | * Also used Ian Stewart's Mathematical Recreations, Scientific |
---|
41 | * American Jul 1994 pp 104-107 |
---|
42 | * also used demon.c and life.c as a guide. |
---|
43 | */ |
---|
44 | |
---|
45 | /*- |
---|
46 | Species Grid Number of Neighbors |
---|
47 | ------- ---- ------------------ |
---|
48 | Ants Square 4 (or 8) |
---|
49 | Bees Hexagon 6 |
---|
50 | Bees Triangle 3 (or 9, 12) |
---|
51 | |
---|
52 | Neighbors 6 and neighbors 3 produce the same Turk ants. |
---|
53 | */ |
---|
54 | |
---|
55 | #ifdef STANDALONE |
---|
56 | #define MODE_ant |
---|
57 | #define PROGCLASS "Ant" |
---|
58 | #define HACK_INIT init_ant |
---|
59 | #define HACK_DRAW draw_ant |
---|
60 | #define ant_opts xlockmore_opts |
---|
61 | #define DEFAULTS "*delay: 1000 \n" \ |
---|
62 | "*count: -3 \n" \ |
---|
63 | "*cycles: 40000 \n" \ |
---|
64 | "*size: -12 \n" \ |
---|
65 | "*ncolors: 64 \n" \ |
---|
66 | "*neighbors: 0 \n" \ |
---|
67 | "*sharpturn: False \n" |
---|
68 | #include "xlockmore.h" /* in xscreensaver distribution */ |
---|
69 | #include "erase.h" |
---|
70 | #else /* STANDALONE */ |
---|
71 | #include "xlock.h" /* in xlockmore distribution */ |
---|
72 | #endif /* STANDALONE */ |
---|
73 | #include "automata.h" |
---|
74 | |
---|
75 | #ifdef MODE_ant |
---|
76 | |
---|
77 | /*- |
---|
78 | * neighbors of 0 randomizes it for 3, 4, 6, 8, 12 (last 2 are less likely) |
---|
79 | */ |
---|
80 | |
---|
81 | #define DEF_NEIGHBORS "0" /* choose random value */ |
---|
82 | #define DEF_TRUCHET "False" |
---|
83 | #define DEF_EYES "False" |
---|
84 | #define DEF_SHARPTURN "False" |
---|
85 | |
---|
86 | static int neighbors; |
---|
87 | static Bool truchet; |
---|
88 | static Bool eyes; |
---|
89 | static Bool sharpturn; |
---|
90 | |
---|
91 | static XrmOptionDescRec opts[] = |
---|
92 | { |
---|
93 | {(char *) "-neighbors", (char *) ".ant.neighbors", XrmoptionSepArg, (caddr_t) NULL}, |
---|
94 | {(char *) "-truchet", (char *) ".ant.truchet", XrmoptionNoArg, (caddr_t) "on"}, |
---|
95 | {(char *) "+truchet", (char *) ".ant.truchet", XrmoptionNoArg, (caddr_t) "off"}, |
---|
96 | {(char *) "-eyes", (char *) ".ant.eyes", XrmoptionNoArg, (caddr_t) "on"}, |
---|
97 | {(char *) "+eyes", (char *) ".ant.eyes", XrmoptionNoArg, (caddr_t) "off"}, |
---|
98 | {(char *) "-sharpturn", (char *) ".ant.sharpturn", XrmoptionNoArg, (caddr_t) "on"}, |
---|
99 | {(char *) "+sharpturn", (char *) ".ant.sharpturn", XrmoptionNoArg, (caddr_t) "off"}, |
---|
100 | {"-neighbors", ".ant.neighbors", XrmoptionSepArg, (caddr_t) 0}, |
---|
101 | {"+neighbors", ".ant.neighbors", XrmoptionSepArg, (caddr_t) 0} |
---|
102 | }; |
---|
103 | static argtype vars[] = |
---|
104 | { |
---|
105 | {(caddr_t *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int}, |
---|
106 | {(caddr_t *) & truchet, (char *) "truchet", (char *) "Truchet", (char *) DEF_TRUCHET, t_Bool}, |
---|
107 | {(caddr_t *) & eyes, (char *) "eyes", (char *) "Eyes", (char *) DEF_EYES, t_Bool}, |
---|
108 | {(caddr_t *) & sharpturn, (char *) "sharpturn", (char *) "SharpTurn", (char *) DEF_SHARPTURN, t_Bool}, |
---|
109 | {(caddr_t *) & neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int} |
---|
110 | }; |
---|
111 | static OptionStruct desc[] = |
---|
112 | { |
---|
113 | {(char *) "-neighbors num", (char *) "squares 4 or 8, hexagons 6, triangles 3 or 12"}, |
---|
114 | {(char *) "-/+truchet", (char *) "turn on/off Truchet lines"}, |
---|
115 | {(char *) "-/+eyes", (char *) "turn on/off eyes"}, |
---|
116 | {(char *) "-/+sharpturn", (char *) "turn on/off sharp turns (6, 8 or 12 neighbors only)"} |
---|
117 | }; |
---|
118 | |
---|
119 | ModeSpecOpt ant_opts = |
---|
120 | {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; |
---|
121 | |
---|
122 | #ifdef USE_MODULES |
---|
123 | const ModStruct ant_description = |
---|
124 | {"ant", |
---|
125 | "init_ant", "draw_ant", "release_ant", |
---|
126 | "refresh_ant", "init_ant", (char *) NULL, &ant_opts, |
---|
127 | 1000, -3, 40000, -12, 64, 1.0, "", |
---|
128 | "Shows Langton's and Turk's generalized ants", 0, NULL}; |
---|
129 | |
---|
130 | #endif |
---|
131 | |
---|
132 | #define ANTBITS(n,w,h)\ |
---|
133 | if ((ap->pixmaps[ap->init_bits]=\ |
---|
134 | XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\ |
---|
135 | free_ant(display,ap); return;} else {ap->init_bits++;} |
---|
136 | |
---|
137 | /* If you change the table you may have to change the following 2 constants */ |
---|
138 | #define STATES 2 |
---|
139 | #define MINANTS 1 |
---|
140 | #define REDRAWSTEP 2000 /* How much tape to draw per cycle */ |
---|
141 | #define MINGRIDSIZE 24 |
---|
142 | #define MINSIZE 1 |
---|
143 | #define MINRANDOMSIZE 5 |
---|
144 | #define ANGLES 360 |
---|
145 | |
---|
146 | typedef struct { |
---|
147 | unsigned char color; |
---|
148 | short direction; |
---|
149 | unsigned char next; |
---|
150 | } statestruct; |
---|
151 | |
---|
152 | typedef struct { |
---|
153 | int col, row; |
---|
154 | short direction; |
---|
155 | unsigned char state; |
---|
156 | } antstruct; |
---|
157 | |
---|
158 | typedef struct { |
---|
159 | Bool painted; |
---|
160 | int neighbors; |
---|
161 | int generation; |
---|
162 | int xs, ys; |
---|
163 | int xb, yb; |
---|
164 | int init_dir; |
---|
165 | int nrows, ncols; |
---|
166 | int width, height; |
---|
167 | unsigned char ncolors, nstates; |
---|
168 | int n; |
---|
169 | int redrawing, redrawpos; |
---|
170 | int truchet; /* Only for Turk modes */ |
---|
171 | int eyes; |
---|
172 | int sharpturn; |
---|
173 | statestruct machine[NUMSTIPPLES * STATES]; |
---|
174 | unsigned char *tape; |
---|
175 | unsigned char *truchet_state; |
---|
176 | antstruct *ants; |
---|
177 | int init_bits; |
---|
178 | unsigned char colors[NUMSTIPPLES - 1]; |
---|
179 | GC stippledGC; |
---|
180 | Pixmap pixmaps[NUMSTIPPLES - 1]; |
---|
181 | union { |
---|
182 | XPoint hexagon[7]; /* Need more than 6 for truchet */ |
---|
183 | XPoint triangle[2][4]; /* Need more than 3 for truchet */ |
---|
184 | } shape; |
---|
185 | } antfarmstruct; |
---|
186 | |
---|
187 | static char plots[] = |
---|
188 | {3, 4, 6, 8, |
---|
189 | #ifdef NUMBER_9 |
---|
190 | 9, |
---|
191 | #endif |
---|
192 | 12}; |
---|
193 | |
---|
194 | #define NEIGHBORKINDS ((long) (sizeof plots / sizeof *plots)) |
---|
195 | #define GOODNEIGHBORKINDS 3 |
---|
196 | |
---|
197 | /* Relative ant moves */ |
---|
198 | #define FS 0 /* Step */ |
---|
199 | #define TRS 1 /* Turn right, then step */ |
---|
200 | #define THRS 2 /* Turn hard right, then step */ |
---|
201 | #define TBS 3 /* Turn back, then step */ |
---|
202 | #define THLS 4 /* Turn hard left, then step */ |
---|
203 | #define TLS 5 /* Turn left, then step */ |
---|
204 | #define SF 6 /* Step */ |
---|
205 | #define STR 7 /* Step then turn right */ |
---|
206 | #define STHR 8 /* Step then turn hard right */ |
---|
207 | #define STB 9 /* Step then turn back */ |
---|
208 | #define STHL 10 /* Step then turn hard left */ |
---|
209 | #define STL 11 /* Step then turn left */ |
---|
210 | |
---|
211 | static antfarmstruct *antfarms = (antfarmstruct *) NULL; |
---|
212 | |
---|
213 | /* LANGTON'S ANT (10) Chaotic after 500, Builder after 10,000 (104p) */ |
---|
214 | /* TURK'S 100 ANT Always chaotic?, tested past 150,000,000 */ |
---|
215 | /* TURK'S 101 ANT Always chaotic? */ |
---|
216 | /* TURK'S 110 ANT Builder at 150 (18p) */ |
---|
217 | /* TURK'S 1000 ANT Always chaotic? */ |
---|
218 | /* TURK'S 1100 SYMMETRIC ANT all even run 1's and 0's are symmetric */ |
---|
219 | /* other examples 1001, 110011, 110000, 1001101 */ |
---|
220 | /* TURK'S 1101 ANT Builder after 250,000 (388p) */ |
---|
221 | /* Once saw a chess horse type builder (i.e. non-45 degree builder) */ |
---|
222 | |
---|
223 | /* BEE ONLY */ |
---|
224 | /* All alternating 10 appear symmetric, no proof (i.e. 10, 1010, etc) */ |
---|
225 | /* Even runs of 0's and 1's are also symmetric */ |
---|
226 | /* I have seen Hexagonal builders but they are more rare. */ |
---|
227 | |
---|
228 | static unsigned char tables[][3 * NUMSTIPPLES * STATES + 2] = |
---|
229 | { |
---|
230 | #if 0 |
---|
231 | /* Here just so you can figure out notation */ |
---|
232 | { /* Langton's ant */ |
---|
233 | 2, 1, |
---|
234 | 1, TLS, 0, 0, TRS, 0 |
---|
235 | }, |
---|
236 | #else |
---|
237 | /* First 2 numbers are the size (ncolors, nstates) */ |
---|
238 | { /* LADDER BUILDER */ |
---|
239 | 4, 1, |
---|
240 | 1, STR, 0, 2, STL, 0, 3, TRS, 0, 0, TLS, 0 |
---|
241 | }, |
---|
242 | { /* SPIRALING PATTERN */ |
---|
243 | 2, 2, |
---|
244 | 1, TLS, 0, 0, FS, 1, |
---|
245 | 1, TRS, 0, 1, TRS, 0 |
---|
246 | }, |
---|
247 | { /* SQUARE (HEXAGON) BUILDER */ |
---|
248 | 2, 2, |
---|
249 | 1, TLS, 0, 0, FS, 1, |
---|
250 | 0, TRS, 0, 1, TRS, 0 |
---|
251 | }, |
---|
252 | #endif |
---|
253 | }; |
---|
254 | |
---|
255 | #define NTABLES (sizeof tables / sizeof tables[0]) |
---|
256 | |
---|
257 | static void |
---|
258 | position_of_neighbor(antfarmstruct * ap, int dir, int *pcol, int *prow) |
---|
259 | { |
---|
260 | int col = *pcol, row = *prow; |
---|
261 | |
---|
262 | if (ap->neighbors == 6) { |
---|
263 | switch (dir) { |
---|
264 | case 0: |
---|
265 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
266 | break; |
---|
267 | case 60: |
---|
268 | if (!(row & 1)) |
---|
269 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
270 | row = (!row) ? ap->nrows - 1 : row - 1; |
---|
271 | break; |
---|
272 | case 120: |
---|
273 | if (row & 1) |
---|
274 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
275 | row = (!row) ? ap->nrows - 1 : row - 1; |
---|
276 | break; |
---|
277 | case 180: |
---|
278 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
279 | break; |
---|
280 | case 240: |
---|
281 | if (row & 1) |
---|
282 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
283 | row = (row + 1 == ap->nrows) ? 0 : row + 1; |
---|
284 | break; |
---|
285 | case 300: |
---|
286 | if (!(row & 1)) |
---|
287 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
288 | row = (row + 1 == ap->nrows) ? 0 : row + 1; |
---|
289 | break; |
---|
290 | default: |
---|
291 | (void) fprintf(stderr, "wrong direction %d\n", dir); |
---|
292 | } |
---|
293 | } else if (ap->neighbors == 4 || ap->neighbors == 8) { |
---|
294 | switch (dir) { |
---|
295 | case 0: |
---|
296 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
297 | break; |
---|
298 | case 45: |
---|
299 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
300 | row = (!row) ? ap->nrows - 1 : row - 1; |
---|
301 | break; |
---|
302 | case 90: |
---|
303 | row = (!row) ? ap->nrows - 1 : row - 1; |
---|
304 | break; |
---|
305 | case 135: |
---|
306 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
307 | row = (!row) ? ap->nrows - 1 : row - 1; |
---|
308 | break; |
---|
309 | case 180: |
---|
310 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
311 | break; |
---|
312 | case 225: |
---|
313 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
314 | row = (row + 1 == ap->nrows) ? 0 : row + 1; |
---|
315 | break; |
---|
316 | case 270: |
---|
317 | row = (row + 1 == ap->nrows) ? 0 : row + 1; |
---|
318 | break; |
---|
319 | case 315: |
---|
320 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
321 | row = (row + 1 == ap->nrows) ? 0 : row + 1; |
---|
322 | break; |
---|
323 | default: |
---|
324 | (void) fprintf(stderr, "wrong direction %d\n", dir); |
---|
325 | } |
---|
326 | } else { /* TRI */ |
---|
327 | if ((col + row) % 2) { /* right */ |
---|
328 | switch (dir) { |
---|
329 | case 0: |
---|
330 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
331 | break; |
---|
332 | case 30: |
---|
333 | case 40: |
---|
334 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
335 | row = (!row) ? ap->nrows - 1 : row - 1; |
---|
336 | break; |
---|
337 | case 60: |
---|
338 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
339 | if (!row) |
---|
340 | row = ap->nrows - 2; |
---|
341 | else if (!(row - 1)) |
---|
342 | row = ap->nrows - 1; |
---|
343 | else |
---|
344 | row = row - 2; |
---|
345 | break; |
---|
346 | case 80: |
---|
347 | case 90: |
---|
348 | if (!row) |
---|
349 | row = ap->nrows - 2; |
---|
350 | else if (!(row - 1)) |
---|
351 | row = ap->nrows - 1; |
---|
352 | else |
---|
353 | row = row - 2; |
---|
354 | break; |
---|
355 | case 120: |
---|
356 | row = (!row) ? ap->nrows - 1 : row - 1; |
---|
357 | break; |
---|
358 | case 150: |
---|
359 | case 160: |
---|
360 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
361 | row = (!row) ? ap->nrows - 1 : row - 1; |
---|
362 | break; |
---|
363 | case 180: |
---|
364 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
365 | break; |
---|
366 | case 200: |
---|
367 | case 210: |
---|
368 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
369 | row = (row + 1 == ap->nrows) ? 0 : row + 1; |
---|
370 | break; |
---|
371 | case 240: |
---|
372 | row = (row + 1 == ap->nrows) ? 0 : row + 1; |
---|
373 | break; |
---|
374 | case 270: |
---|
375 | case 280: |
---|
376 | if (row + 1 == ap->nrows) |
---|
377 | row = 1; |
---|
378 | else if (row + 2 == ap->nrows) |
---|
379 | row = 0; |
---|
380 | else |
---|
381 | row = row + 2; |
---|
382 | break; |
---|
383 | case 300: |
---|
384 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
385 | if (row + 1 == ap->nrows) |
---|
386 | row = 1; |
---|
387 | else if (row + 2 == ap->nrows) |
---|
388 | row = 0; |
---|
389 | else |
---|
390 | row = row + 2; |
---|
391 | break; |
---|
392 | case 320: |
---|
393 | case 330: |
---|
394 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
395 | row = (row + 1 == ap->nrows) ? 0 : row + 1; |
---|
396 | break; |
---|
397 | default: |
---|
398 | (void) fprintf(stderr, "wrong direction %d\n", dir); |
---|
399 | } |
---|
400 | } else { /* left */ |
---|
401 | switch (dir) { |
---|
402 | case 0: |
---|
403 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
404 | break; |
---|
405 | case 30: |
---|
406 | case 40: |
---|
407 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
408 | row = (row + 1 == ap->nrows) ? 0 : row + 1; |
---|
409 | break; |
---|
410 | case 60: |
---|
411 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
412 | if (row + 1 == ap->nrows) |
---|
413 | row = 1; |
---|
414 | else if (row + 2 == ap->nrows) |
---|
415 | row = 0; |
---|
416 | else |
---|
417 | row = row + 2; |
---|
418 | break; |
---|
419 | case 80: |
---|
420 | case 90: |
---|
421 | if (row + 1 == ap->nrows) |
---|
422 | row = 1; |
---|
423 | else if (row + 2 == ap->nrows) |
---|
424 | row = 0; |
---|
425 | else |
---|
426 | row = row + 2; |
---|
427 | break; |
---|
428 | case 120: |
---|
429 | row = (row + 1 == ap->nrows) ? 0 : row + 1; |
---|
430 | break; |
---|
431 | case 150: |
---|
432 | case 160: |
---|
433 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
434 | row = (row + 1 == ap->nrows) ? 0 : row + 1; |
---|
435 | break; |
---|
436 | case 180: |
---|
437 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
438 | break; |
---|
439 | case 200: |
---|
440 | case 210: |
---|
441 | col = (!col) ? ap->ncols - 1 : col - 1; |
---|
442 | row = (!row) ? ap->nrows - 1 : row - 1; |
---|
443 | break; |
---|
444 | case 240: |
---|
445 | row = (!row) ? ap->nrows - 1 : row - 1; |
---|
446 | break; |
---|
447 | case 270: |
---|
448 | case 280: |
---|
449 | if (!row) |
---|
450 | row = ap->nrows - 2; |
---|
451 | else if (row == 1) |
---|
452 | row = ap->nrows - 1; |
---|
453 | else |
---|
454 | row = row - 2; |
---|
455 | break; |
---|
456 | case 300: |
---|
457 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
458 | if (!row) |
---|
459 | row = ap->nrows - 2; |
---|
460 | else if (row == 1) |
---|
461 | row = ap->nrows - 1; |
---|
462 | else |
---|
463 | row = row - 2; |
---|
464 | break; |
---|
465 | case 320: |
---|
466 | case 330: |
---|
467 | col = (col + 1 == ap->ncols) ? 0 : col + 1; |
---|
468 | row = (!row) ? ap->nrows - 1 : row - 1; |
---|
469 | break; |
---|
470 | default: |
---|
471 | (void) fprintf(stderr, "wrong direction %d\n", dir); |
---|
472 | } |
---|
473 | } |
---|
474 | } |
---|
475 | *pcol = col; |
---|
476 | *prow = row; |
---|
477 | } |
---|
478 | |
---|
479 | static void |
---|
480 | fillcell(ModeInfo * mi, GC gc, int col, int row) |
---|
481 | { |
---|
482 | antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; |
---|
483 | |
---|
484 | if (ap->neighbors == 6) { |
---|
485 | int ccol = 2 * col + !(row & 1), crow = 2 * row; |
---|
486 | |
---|
487 | ap->shape.hexagon[0].x = ap->xb + ccol * ap->xs; |
---|
488 | ap->shape.hexagon[0].y = ap->yb + crow * ap->ys; |
---|
489 | if (ap->xs == 1 && ap->ys == 1) |
---|
490 | XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc, |
---|
491 | ap->shape.hexagon[0].x, ap->shape.hexagon[0].y); |
---|
492 | else |
---|
493 | XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, |
---|
494 | ap->shape.hexagon, 6, Convex, CoordModePrevious); |
---|
495 | } else if (ap->neighbors == 4 || ap->neighbors == 8) { |
---|
496 | XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc, |
---|
497 | ap->xb + ap->xs * col, ap->yb + ap->ys * row, |
---|
498 | ap->xs - (ap->xs > 3), ap->ys - (ap->ys > 3)); |
---|
499 | } else { /* TRI */ |
---|
500 | int orient = (col + row) % 2; /* O left 1 right */ |
---|
501 | |
---|
502 | ap->shape.triangle[orient][0].x = ap->xb + col * ap->xs; |
---|
503 | ap->shape.triangle[orient][0].y = ap->yb + row * ap->ys; |
---|
504 | if (ap->xs <= 3 || ap->ys <= 3) |
---|
505 | XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc, |
---|
506 | ((orient) ? -1 : 1) + ap->shape.triangle[orient][0].x, |
---|
507 | ap->shape.triangle[orient][0].y); |
---|
508 | else { |
---|
509 | if (orient) |
---|
510 | ap->shape.triangle[orient][0].x += (ap->xs / 2 - 1); |
---|
511 | else |
---|
512 | ap->shape.triangle[orient][0].x -= (ap->xs / 2 - 1); |
---|
513 | XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, |
---|
514 | ap->shape.triangle[orient], 3, Convex, CoordModePrevious); |
---|
515 | } |
---|
516 | } |
---|
517 | } |
---|
518 | |
---|
519 | static void |
---|
520 | truchetcell(ModeInfo * mi, int col, int row, int truchetstate) |
---|
521 | { |
---|
522 | antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; |
---|
523 | |
---|
524 | if (ap->neighbors == 6) { |
---|
525 | |
---|
526 | int ccol = 2 * col + !(row & 1), crow = 2 * row; |
---|
527 | int side; |
---|
528 | int fudge = 7; /* fudge because the hexagons are not exact */ |
---|
529 | XPoint hex, hex2; |
---|
530 | |
---|
531 | if (ap->sharpturn) { |
---|
532 | hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs / 2.0) - 1; |
---|
533 | hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys / 2.0) - 1; |
---|
534 | for (side = 0; side < 6; side++) { |
---|
535 | if (side) { |
---|
536 | hex.x += ap->shape.hexagon[side].x; |
---|
537 | hex.y += ap->shape.hexagon[side].y; |
---|
538 | } |
---|
539 | if (truchetstate == side % 2) |
---|
540 | XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), |
---|
541 | hex.x, hex.y, ap->xs, ap->ys, |
---|
542 | ((570 - (side * 60) + fudge) % 360) * 64, (120 - 2 * fudge) * 64); |
---|
543 | } |
---|
544 | } else { |
---|
545 | /* Very crude approx of Sqrt 3, so it will not cause drawing errors. */ |
---|
546 | hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs * 1.6 / 2.0) - 1; |
---|
547 | hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys * 1.6 / 2.0) - 1; |
---|
548 | for (side = 0; side < 6; side++) { |
---|
549 | if (side) { |
---|
550 | hex.x += ap->shape.hexagon[side].x; |
---|
551 | hex.y += ap->shape.hexagon[side].y; |
---|
552 | } |
---|
553 | hex2.x = hex.x + ap->shape.hexagon[side + 1].x / 2; |
---|
554 | hex2.y = hex.y + ap->shape.hexagon[side + 1].y / 2 + 1; |
---|
555 | /* Lots of fudging here */ |
---|
556 | if (side == 1) { |
---|
557 | hex2.x += (short) (ap->xs * 0.1 + 1); |
---|
558 | hex2.y += (short) (ap->ys * 0.1 - ((ap->ys > 5) ? 1 : 0)); |
---|
559 | } else if (side == 2) { |
---|
560 | hex2.x += (short) (ap->xs * 0.1); |
---|
561 | } else if (side == 4) { |
---|
562 | hex2.x += (short) (ap->xs * 0.1); |
---|
563 | hex2.y += (short) (ap->ys * 0.1 - 1); |
---|
564 | } else if (side == 5) { |
---|
565 | hex2.x += (short) (ap->xs * 0.5); |
---|
566 | hex2.y += (short) (-ap->ys * 0.3 + 1); |
---|
567 | } |
---|
568 | if (truchetstate == side % 3) |
---|
569 | /* Crude approx of 120 deg, so it will not cause drawing errors. */ |
---|
570 | XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), |
---|
571 | hex2.x, hex2.y, |
---|
572 | (int) ((double) ap->xs * 1.5), (int) ((double) ap->ys * 1.5), |
---|
573 | ((555 - (side * 60)) % 360) * 64, 90 * 64); |
---|
574 | } |
---|
575 | } |
---|
576 | } else if (ap->neighbors == 4) { |
---|
577 | if (truchetstate) { |
---|
578 | XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), |
---|
579 | ap->xb + ap->xs * col - ap->xs / 2 + 1, |
---|
580 | ap->yb + ap->ys * row + ap->ys / 2 - 1, |
---|
581 | ap->xs - 2, ap->ys - 2, |
---|
582 | 0 * 64, 90 * 64); |
---|
583 | XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), |
---|
584 | ap->xb + ap->xs * col + ap->xs / 2 - 1, |
---|
585 | ap->yb + ap->ys * row - ap->ys / 2 + 1, |
---|
586 | ap->xs - 2, ap->ys - 2, |
---|
587 | -90 * 64, -90 * 64); |
---|
588 | } else { |
---|
589 | XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), |
---|
590 | ap->xb + ap->xs * col - ap->xs / 2 + 1, |
---|
591 | ap->yb + ap->ys * row - ap->ys / 2 + 1, |
---|
592 | ap->xs - 2, ap->ys - 2, |
---|
593 | 0 * 64, -90 * 64); |
---|
594 | XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), |
---|
595 | ap->xb + ap->xs * col + ap->xs / 2 - 1, |
---|
596 | ap->yb + ap->ys * row + ap->ys / 2 - 1, |
---|
597 | ap->xs - 2, ap->ys - 2, |
---|
598 | 90 * 64, 90 * 64); |
---|
599 | } |
---|
600 | } else if (ap->neighbors == 3) { |
---|
601 | int orient = (col + row) % 2; /* O left 1 right */ |
---|
602 | int side, ang; |
---|
603 | int fudge = 7; /* fudge because the triangles are not exact */ |
---|
604 | double fudge2 = 1.18; |
---|
605 | XPoint tri; |
---|
606 | |
---|
607 | tri.x = ap->xb + col * ap->xs; |
---|
608 | tri.y = ap->yb + row * ap->ys; |
---|
609 | if (orient) { |
---|
610 | tri.x += (ap->xs / 2 - 1); |
---|
611 | } else { |
---|
612 | tri.x -= (ap->xs / 2 - 1); |
---|
613 | } |
---|
614 | for (side = 0; side < 3; side++) { |
---|
615 | if (side > 0) { |
---|
616 | tri.x += ap->shape.triangle[orient][side].x; |
---|
617 | tri.y += ap->shape.triangle[orient][side].y; |
---|
618 | } |
---|
619 | if (truchetstate == side) { |
---|
620 | if (orient) |
---|
621 | ang = (510 - side * 120) % 360; /* Right */ |
---|
622 | else |
---|
623 | ang = (690 - side * 120) % 360; /* Left */ |
---|
624 | XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), |
---|
625 | (int) (tri.x - ap->xs * fudge2 / 2), |
---|
626 | (int) (tri.y - 3 * ap->ys * fudge2 / 4), |
---|
627 | (unsigned int) (ap->xs * fudge2), |
---|
628 | (unsigned int) (3 * ap->ys * fudge2 / 2), |
---|
629 | (ang + fudge) * 64, (60 - 2 * fudge) * 64); |
---|
630 | } |
---|
631 | } |
---|
632 | } |
---|
633 | } |
---|
634 | |
---|
635 | static void |
---|
636 | drawcell(ModeInfo * mi, int col, int row, unsigned char color) |
---|
637 | { |
---|
638 | antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; |
---|
639 | GC gc; |
---|
640 | |
---|
641 | if (!color) { |
---|
642 | XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); |
---|
643 | gc = MI_GC(mi); |
---|
644 | } else if (MI_NPIXELS(mi) > 2) { |
---|
645 | XSetForeground(MI_DISPLAY(mi), MI_GC(mi), |
---|
646 | MI_PIXEL(mi, ap->colors[color - 1])); |
---|
647 | gc = MI_GC(mi); |
---|
648 | } else { |
---|
649 | XGCValues gcv; |
---|
650 | |
---|
651 | gcv.stipple = ap->pixmaps[color - 1]; |
---|
652 | gcv.foreground = MI_WHITE_PIXEL(mi); |
---|
653 | gcv.background = MI_BLACK_PIXEL(mi); |
---|
654 | XChangeGC(MI_DISPLAY(mi), ap->stippledGC, |
---|
655 | GCStipple | GCForeground | GCBackground, &gcv); |
---|
656 | gc = ap->stippledGC; |
---|
657 | } |
---|
658 | fillcell(mi, gc, col, row); |
---|
659 | } |
---|
660 | |
---|
661 | static void |
---|
662 | drawtruchet(ModeInfo * mi, int col, int row, |
---|
663 | unsigned char color, unsigned char truchetstate) |
---|
664 | { |
---|
665 | antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; |
---|
666 | |
---|
667 | if (!color) |
---|
668 | XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); |
---|
669 | else if (MI_NPIXELS(mi) > 2 || color > ap->ncolors / 2) |
---|
670 | XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); |
---|
671 | else |
---|
672 | XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); |
---|
673 | truchetcell(mi, col, row, truchetstate); |
---|
674 | } |
---|
675 | |
---|
676 | static void |
---|
677 | draw_anant(ModeInfo * mi, int direction, int col, int row) |
---|
678 | { |
---|
679 | antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; |
---|
680 | Display *display = MI_DISPLAY(mi); |
---|
681 | Window window = MI_WINDOW(mi); |
---|
682 | |
---|
683 | XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi)); |
---|
684 | fillcell(mi, MI_GC(mi), col, row); |
---|
685 | if (ap->eyes) { /* Draw Eyes */ |
---|
686 | XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi)); |
---|
687 | if (ap->neighbors == 6) { |
---|
688 | int ccol = 2 * col + !(row & 1), crow = 2 * row; |
---|
689 | int side, ang; |
---|
690 | XPoint hex; |
---|
691 | |
---|
692 | if (!(ap->xs > 3 && ap->ys > 3)) |
---|
693 | return; |
---|
694 | hex.x = ap->xb + ccol * ap->xs; |
---|
695 | hex.y = ap->yb + crow * ap->ys + ap->ys / 2; |
---|
696 | ang = direction * ap->neighbors / ANGLES; |
---|
697 | for (side = 0; side < ap->neighbors; side++) { |
---|
698 | if (side) { |
---|
699 | hex.x -= ap->shape.hexagon[side].x / 2; |
---|
700 | hex.y += ap->shape.hexagon[side].y / 2; |
---|
701 | } |
---|
702 | if (side == (ap->neighbors + ang - 2) % ap->neighbors) |
---|
703 | XDrawPoint(display, window, MI_GC(mi), hex.x, hex.y); |
---|
704 | if (side == (ap->neighbors + ang - 1) % ap->neighbors) |
---|
705 | XDrawPoint(display, window, MI_GC(mi), hex.x, hex.y); |
---|
706 | } |
---|
707 | } else if (ap->neighbors == 4 || ap->neighbors == 8) { |
---|
708 | if (!(ap->xs > 3 && ap->ys > 3)) |
---|
709 | return; |
---|
710 | switch (direction) { |
---|
711 | case 0: |
---|
712 | XDrawPoint(display, window, MI_GC(mi), |
---|
713 | ap->xb + ap->xs * (col + 1) - 3, |
---|
714 | ap->yb + ap->ys * row + ap->ys / 2 - 2); |
---|
715 | XDrawPoint(display, window, MI_GC(mi), |
---|
716 | ap->xb + ap->xs * (col + 1) - 3, |
---|
717 | ap->yb + ap->ys * row + ap->ys / 2); |
---|
718 | break; |
---|
719 | case 45: |
---|
720 | XDrawPoint(display, window, MI_GC(mi), |
---|
721 | ap->xb + ap->xs * (col + 1) - 4, |
---|
722 | ap->yb + ap->ys * row + 1); |
---|
723 | XDrawPoint(display, window, MI_GC(mi), |
---|
724 | ap->xb + ap->xs * (col + 1) - 3, |
---|
725 | ap->yb + ap->ys * row + 2); |
---|
726 | break; |
---|
727 | case 90: |
---|
728 | XDrawPoint(display, window, MI_GC(mi), |
---|
729 | ap->xb + ap->xs * col + ap->xs / 2 - 2, |
---|
730 | ap->yb + ap->ys * row + 1); |
---|
731 | XDrawPoint(display, window, MI_GC(mi), |
---|
732 | ap->xb + ap->xs * col + ap->xs / 2, |
---|
733 | ap->yb + ap->ys * row + 1); |
---|
734 | break; |
---|
735 | case 135: |
---|
736 | XDrawPoint(display, window, MI_GC(mi), |
---|
737 | ap->xb + ap->xs * col + 2, |
---|
738 | ap->yb + ap->ys * row + 1); |
---|
739 | XDrawPoint(display, window, MI_GC(mi), |
---|
740 | ap->xb + ap->xs * col + 1, |
---|
741 | ap->yb + ap->ys * row + 2); |
---|
742 | break; |
---|
743 | case 180: |
---|
744 | XDrawPoint(display, window, MI_GC(mi), |
---|
745 | ap->xb + ap->xs * col + 1, |
---|
746 | ap->yb + ap->ys * row + ap->ys / 2 - 2); |
---|
747 | XDrawPoint(display, window, MI_GC(mi), |
---|
748 | ap->xb + ap->xs * col + 1, |
---|
749 | ap->yb + ap->ys * row + ap->ys / 2); |
---|
750 | break; |
---|
751 | case 225: |
---|
752 | XDrawPoint(display, window, MI_GC(mi), |
---|
753 | ap->xb + ap->xs * col + 2, |
---|
754 | ap->yb + ap->ys * (row + 1) - 3); |
---|
755 | XDrawPoint(display, window, MI_GC(mi), |
---|
756 | ap->xb + ap->xs * col + 1, |
---|
757 | ap->yb + ap->ys * (row + 1) - 4); |
---|
758 | break; |
---|
759 | case 270: |
---|
760 | XDrawPoint(display, window, MI_GC(mi), |
---|
761 | ap->xb + ap->xs * col + ap->xs / 2 - 2, |
---|
762 | ap->yb + ap->ys * (row + 1) - 3); |
---|
763 | XDrawPoint(display, window, MI_GC(mi), |
---|
764 | ap->xb + ap->xs * col + ap->xs / 2, |
---|
765 | ap->yb + ap->ys * (row + 1) - 3); |
---|
766 | break; |
---|
767 | case 315: |
---|
768 | XDrawPoint(display, window, MI_GC(mi), |
---|
769 | ap->xb + ap->xs * (col + 1) - 4, |
---|
770 | ap->yb + ap->ys * (row + 1) - 3); |
---|
771 | XDrawPoint(display, window, MI_GC(mi), |
---|
772 | ap->xb + ap->xs * (col + 1) - 3, |
---|
773 | ap->yb + ap->ys * (row + 1) - 4); |
---|
774 | break; |
---|
775 | default: |
---|
776 | (void) fprintf(stderr, "wrong eyes direction %d for ant eyes\n", direction); |
---|
777 | } |
---|
778 | } else { /* TRI */ |
---|
779 | int orient = (col + row) % 2; /* O left 1 right */ |
---|
780 | int side, ang; |
---|
781 | XPoint tri; |
---|
782 | |
---|
783 | if (!(ap->xs > 6 && ap->ys > 6)) |
---|
784 | return; |
---|
785 | tri.x = ap->xb + col * ap->xs; |
---|
786 | tri.y = ap->yb + row * ap->ys; |
---|
787 | if (orient) |
---|
788 | tri.x += (ap->xs / 6 - 1); |
---|
789 | else |
---|
790 | tri.x -= (ap->xs / 6 - 1); |
---|
791 | ang = direction * ap->neighbors / ANGLES; |
---|
792 | /* approx... does not work that well for even numbers */ |
---|
793 | if ( |
---|
794 | #ifdef NUMBER_9 |
---|
795 | ap->neighbors == 9 || |
---|
796 | #endif |
---|
797 | ap->neighbors == 12) { |
---|
798 | #ifdef UNDER_CONSTRUCTION |
---|
799 | /* Not sure why this does not work */ |
---|
800 | ang = ((ang + ap->neighbors / 6) / (ap->neighbors / 3)) % 3; |
---|
801 | #else |
---|
802 | return; |
---|
803 | #endif |
---|
804 | } |
---|
805 | for (side = 0; side < 3; side++) { |
---|
806 | if (side) { |
---|
807 | tri.x += ap->shape.triangle[orient][side].x / 3; |
---|
808 | tri.y += ap->shape.triangle[orient][side].y / 3; |
---|
809 | } |
---|
810 | /* Either you have the eyes in back or one eye in front */ |
---|
811 | #if 0 |
---|
812 | if (side == ang) |
---|
813 | XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y); |
---|
814 | #else |
---|
815 | if (side == (ang + 2) % 3) |
---|
816 | XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y); |
---|
817 | if (side == (ang + 1) % 3) |
---|
818 | XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y); |
---|
819 | #endif |
---|
820 | } |
---|
821 | } |
---|
822 | } |
---|
823 | } |
---|
824 | |
---|
825 | #if 0 |
---|
826 | static void |
---|
827 | RandomSoup(mi) |
---|
828 | ModeInfo *mi; |
---|
829 | { |
---|
830 | antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; |
---|
831 | int row, col, mrow = 0; |
---|
832 | |
---|
833 | for (row = 0; row < ap->nrows; ++row) { |
---|
834 | for (col = 0; col < ap->ncols; ++col) { |
---|
835 | ap->old[col + mrow] = (unsigned char) NRAND((int) ap->ncolors); |
---|
836 | drawcell(mi, col, row, ap->old[col + mrow]); |
---|
837 | } |
---|
838 | mrow += ap->nrows; |
---|
839 | } |
---|
840 | } |
---|
841 | |
---|
842 | #endif |
---|
843 | |
---|
844 | static short |
---|
845 | fromTableDirection(unsigned char dir, int local_neighbors) |
---|
846 | { |
---|
847 | /* Crafted to work for odd number of neighbors */ |
---|
848 | switch (dir) { |
---|
849 | case FS: |
---|
850 | return 0; |
---|
851 | case TLS: |
---|
852 | return (ANGLES / local_neighbors); |
---|
853 | case THLS: |
---|
854 | return (2 * ANGLES / local_neighbors); |
---|
855 | case TBS: |
---|
856 | return ((local_neighbors / 2) * ANGLES / local_neighbors); |
---|
857 | case THRS: |
---|
858 | return (ANGLES - 2 * ANGLES / local_neighbors); |
---|
859 | case TRS: |
---|
860 | return (ANGLES - ANGLES / local_neighbors); |
---|
861 | case SF: |
---|
862 | return ANGLES; |
---|
863 | case STL: |
---|
864 | return (ANGLES + ANGLES / local_neighbors); |
---|
865 | case STHL: |
---|
866 | return (ANGLES + 2 * ANGLES / local_neighbors); |
---|
867 | case STB: |
---|
868 | return (ANGLES + (local_neighbors / 2) * ANGLES / local_neighbors); |
---|
869 | case STHR: |
---|
870 | return (2 * ANGLES - 2 * ANGLES / local_neighbors); |
---|
871 | case STR: |
---|
872 | return (2 * ANGLES - ANGLES / local_neighbors); |
---|
873 | default: |
---|
874 | (void) fprintf(stderr, "wrong direction %d from table\n", dir); |
---|
875 | } |
---|
876 | return -1; |
---|
877 | } |
---|
878 | |
---|
879 | static void |
---|
880 | getTable(ModeInfo * mi, int i) |
---|
881 | { |
---|
882 | antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; |
---|
883 | int j, total; |
---|
884 | unsigned char *patptr; |
---|
885 | |
---|
886 | patptr = &tables[i][0]; |
---|
887 | ap->ncolors = *patptr++; |
---|
888 | ap->nstates = *patptr++; |
---|
889 | total = ap->ncolors * ap->nstates; |
---|
890 | if (MI_IS_VERBOSE(mi)) |
---|
891 | (void) fprintf(stdout, |
---|
892 | "ants %d, neighbors %d, table number %d, colors %d, states %d\n", |
---|
893 | ap->n, ap->neighbors, i, ap->ncolors, ap->nstates); |
---|
894 | for (j = 0; j < total; j++) { |
---|
895 | ap->machine[j].color = *patptr++; |
---|
896 | if (ap->sharpturn && ap->neighbors > 4) { |
---|
897 | int k = *patptr++; |
---|
898 | |
---|
899 | switch (k) { |
---|
900 | case TRS: |
---|
901 | k = THRS; |
---|
902 | break; |
---|
903 | case THRS: |
---|
904 | k = TRS; |
---|
905 | break; |
---|
906 | case THLS: |
---|
907 | k = TLS; |
---|
908 | break; |
---|
909 | case TLS: |
---|
910 | k = THLS; |
---|
911 | break; |
---|
912 | case STR: |
---|
913 | k = STHR; |
---|
914 | break; |
---|
915 | case STHR: |
---|
916 | k = STR; |
---|
917 | break; |
---|
918 | case STHL: |
---|
919 | k = STL; |
---|
920 | break; |
---|
921 | case STL: |
---|
922 | k = STHL; |
---|
923 | break; |
---|
924 | default: |
---|
925 | break; |
---|
926 | } |
---|
927 | ap->machine[j].direction = fromTableDirection(k, ap->neighbors); |
---|
928 | } else { |
---|
929 | ap->machine[j].direction = fromTableDirection(*patptr++, ap->neighbors); |
---|
930 | } |
---|
931 | ap->machine[j].next = *patptr++; |
---|
932 | } |
---|
933 | ap->truchet = False; |
---|
934 | } |
---|
935 | |
---|
936 | static void |
---|
937 | getTurk(ModeInfo * mi, int i) |
---|
938 | { |
---|
939 | antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; |
---|
940 | int power2, j, number, total; |
---|
941 | |
---|
942 | /* To force a number, say <i = 2;> has i + 2 (or 4) binary digits */ |
---|
943 | power2 = 1 << (i + 1); |
---|
944 | /* Do not want numbers which in binary are all 1's. */ |
---|
945 | number = NRAND(power2 - 1) + power2; |
---|
946 | /* To force a particular number, say <number = 10;> */ |
---|
947 | |
---|
948 | ap->ncolors = i + 2; |
---|
949 | ap->nstates = 1; |
---|
950 | total = ap->ncolors * ap->nstates; |
---|
951 | for (j = 0; j < total; j++) { |
---|
952 | ap->machine[j].color = (j + 1) % total; |
---|
953 | if (ap->sharpturn && ap->neighbors > 4) { |
---|
954 | ap->machine[j].direction = (power2 & number) ? |
---|
955 | fromTableDirection(THRS, ap->neighbors) : |
---|
956 | fromTableDirection(THLS, ap->neighbors); |
---|
957 | } else { |
---|
958 | ap->machine[j].direction = (power2 & number) ? |
---|
959 | fromTableDirection(TRS, ap->neighbors) : |
---|
960 | fromTableDirection(TLS, ap->neighbors); |
---|
961 | } |
---|
962 | ap->machine[j].next = 0; |
---|
963 | power2 >>= 1; |
---|
964 | } |
---|
965 | ap->truchet = (ap->truchet && ap->xs > 2 && ap->ys > 2 && |
---|
966 | (ap->neighbors == 3 || ap->neighbors == 4 || ap->neighbors == 6)); |
---|
967 | if (MI_IS_VERBOSE(mi)) |
---|
968 | (void) fprintf(stdout, |
---|
969 | "ants %d, neighbors %d, Turk's number %d, colors %d\n", |
---|
970 | ap->n, ap->neighbors, number, ap->ncolors); |
---|
971 | } |
---|
972 | |
---|
973 | static void |
---|
974 | free_ant(Display *display, antfarmstruct *ap) |
---|
975 | { |
---|
976 | int shade; |
---|
977 | |
---|
978 | if (ap->stippledGC != None) { |
---|
979 | XFreeGC(display, ap->stippledGC); |
---|
980 | ap->stippledGC = None; |
---|
981 | } |
---|
982 | for (shade = 0; shade < ap->init_bits; shade++) { |
---|
983 | XFreePixmap(display, ap->pixmaps[shade]); |
---|
984 | } |
---|
985 | ap->init_bits = 0; |
---|
986 | if (ap->tape != NULL) { |
---|
987 | (void) free((void *) ap->tape); |
---|
988 | ap->tape = (unsigned char *) NULL; |
---|
989 | } |
---|
990 | if (ap->ants != NULL) { |
---|
991 | (void) free((void *) ap->ants); |
---|
992 | ap->ants = (antstruct *) NULL; |
---|
993 | } |
---|
994 | if (ap->truchet_state != NULL) { |
---|
995 | (void) free((void *) ap->truchet_state); |
---|
996 | ap->truchet_state = (unsigned char *) NULL; |
---|
997 | } |
---|
998 | } |
---|
999 | |
---|
1000 | void |
---|
1001 | init_ant(ModeInfo * mi) |
---|
1002 | { |
---|
1003 | Display *display = MI_DISPLAY(mi); |
---|
1004 | Window window = MI_WINDOW(mi); |
---|
1005 | int size = MI_SIZE(mi); |
---|
1006 | antfarmstruct *ap; |
---|
1007 | int col, row, dir; |
---|
1008 | int i; |
---|
1009 | |
---|
1010 | if (antfarms == NULL) { |
---|
1011 | if ((antfarms = (antfarmstruct *) calloc(MI_NUM_SCREENS(mi), |
---|
1012 | sizeof (antfarmstruct))) == NULL) |
---|
1013 | return; |
---|
1014 | } |
---|
1015 | ap = &antfarms[MI_SCREEN(mi)]; |
---|
1016 | |
---|
1017 | ap->redrawing = 0; |
---|
1018 | if (MI_NPIXELS(mi) <= 2) { |
---|
1019 | if (ap->stippledGC == None) { |
---|
1020 | XGCValues gcv; |
---|
1021 | |
---|
1022 | gcv.fill_style = FillOpaqueStippled; |
---|
1023 | if ((ap->stippledGC = XCreateGC(display, window, GCFillStyle, |
---|
1024 | &gcv)) == None) { |
---|
1025 | free_ant(display, ap); |
---|
1026 | return; |
---|
1027 | } |
---|
1028 | } |
---|
1029 | if (ap->init_bits == 0) { |
---|
1030 | for (i = 1; i < NUMSTIPPLES; i++) { |
---|
1031 | ANTBITS(stipples[i], STIPPLESIZE, STIPPLESIZE); |
---|
1032 | } |
---|
1033 | } |
---|
1034 | } |
---|
1035 | ap->generation = 0; |
---|
1036 | ap->n = MI_COUNT(mi); |
---|
1037 | if (ap->n < -MINANTS) { |
---|
1038 | /* if ap->n is random ... the size can change */ |
---|
1039 | if (ap->ants != NULL) { |
---|
1040 | (void) free((void *) ap->ants); |
---|
1041 | ap->ants = (antstruct *) NULL; |
---|
1042 | } |
---|
1043 | ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS; |
---|
1044 | } else if (ap->n < MINANTS) |
---|
1045 | ap->n = MINANTS; |
---|
1046 | |
---|
1047 | ap->width = MI_WIDTH(mi); |
---|
1048 | ap->height = MI_HEIGHT(mi); |
---|
1049 | |
---|
1050 | for (i = 0; i < NEIGHBORKINDS; i++) { |
---|
1051 | if (neighbors == plots[i]) { |
---|
1052 | ap->neighbors = plots[i]; |
---|
1053 | break; |
---|
1054 | } |
---|
1055 | if (i == NEIGHBORKINDS - 1) { |
---|
1056 | if (!NRAND(10)) { |
---|
1057 | /* Make above 6 rare */ |
---|
1058 | ap->neighbors = plots[NRAND(NEIGHBORKINDS)]; |
---|
1059 | } else { |
---|
1060 | ap->neighbors = plots[NRAND(GOODNEIGHBORKINDS)]; |
---|
1061 | } |
---|
1062 | break; |
---|
1063 | } |
---|
1064 | } |
---|
1065 | |
---|
1066 | if (ap->neighbors == 6) { |
---|
1067 | int nccols, ncrows; |
---|
1068 | |
---|
1069 | if (ap->width < 8) |
---|
1070 | ap->width = 8; |
---|
1071 | if (ap->height < 8) |
---|
1072 | ap->height = 8; |
---|
1073 | if (size < -MINSIZE) { |
---|
1074 | ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) / |
---|
1075 | MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; |
---|
1076 | if (ap->ys < MINRANDOMSIZE) |
---|
1077 | ap->ys = MIN(MINRANDOMSIZE, |
---|
1078 | MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE)); |
---|
1079 | } else if (size < MINSIZE) { |
---|
1080 | if (!size) |
---|
1081 | ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE); |
---|
1082 | else |
---|
1083 | ap->ys = MINSIZE; |
---|
1084 | } else |
---|
1085 | ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) / |
---|
1086 | MINGRIDSIZE)); |
---|
1087 | ap->xs = ap->ys; |
---|
1088 | nccols = MAX(ap->width / ap->xs - 2, 2); |
---|
1089 | ncrows = MAX(ap->height / ap->ys - 1, 4); |
---|
1090 | ap->ncols = nccols / 2; |
---|
1091 | ap->nrows = 2 * (ncrows / 4); |
---|
1092 | ap->xb = (ap->width - ap->xs * nccols) / 2 + ap->xs / 2; |
---|
1093 | ap->yb = (ap->height - ap->ys * (ncrows / 2) * 2) / 2 + ap->ys - 2; |
---|
1094 | for (i = 0; i < 6; i++) { |
---|
1095 | ap->shape.hexagon[i].x = (ap->xs - 1) * hexagonUnit[i].x; |
---|
1096 | ap->shape.hexagon[i].y = ((ap->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3; |
---|
1097 | } |
---|
1098 | /* Avoid array bounds read of hexagonUnit */ |
---|
1099 | ap->shape.hexagon[6].x = 0; |
---|
1100 | ap->shape.hexagon[6].y = 0; |
---|
1101 | } else if (ap->neighbors == 4 || ap->neighbors == 8) { |
---|
1102 | if (size < -MINSIZE) { |
---|
1103 | ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) / |
---|
1104 | MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; |
---|
1105 | if (ap->ys < MINRANDOMSIZE) |
---|
1106 | ap->ys = MIN(MINRANDOMSIZE, |
---|
1107 | MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE)); |
---|
1108 | } else if (size < MINSIZE) { |
---|
1109 | if (!size) |
---|
1110 | ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE); |
---|
1111 | else |
---|
1112 | ap->ys = MINSIZE; |
---|
1113 | } else |
---|
1114 | ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) / |
---|
1115 | MINGRIDSIZE)); |
---|
1116 | ap->xs = ap->ys; |
---|
1117 | ap->ncols = MAX(ap->width / ap->xs, 2); |
---|
1118 | ap->nrows = MAX(ap->height / ap->ys, 2); |
---|
1119 | ap->xb = (ap->width - ap->xs * ap->ncols) / 2; |
---|
1120 | ap->yb = (ap->height - ap->ys * ap->nrows) / 2; |
---|
1121 | } else { /* TRI */ |
---|
1122 | int orient; |
---|
1123 | |
---|
1124 | if (ap->width < 2) |
---|
1125 | ap->width = 2; |
---|
1126 | if (ap->height < 2) |
---|
1127 | ap->height = 2; |
---|
1128 | if (size < -MINSIZE) { |
---|
1129 | ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) / |
---|
1130 | MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; |
---|
1131 | if (ap->ys < MINRANDOMSIZE) |
---|
1132 | ap->ys = MIN(MINRANDOMSIZE, |
---|
1133 | MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE)); |
---|
1134 | } else if (size < MINSIZE) { |
---|
1135 | if (!size) |
---|
1136 | ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE); |
---|
1137 | else |
---|
1138 | ap->ys = MINSIZE; |
---|
1139 | } else |
---|
1140 | ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) / |
---|
1141 | MINGRIDSIZE)); |
---|
1142 | ap->xs = (int) (1.52 * ap->ys); |
---|
1143 | ap->ncols = (MAX(ap->width / ap->xs - 1, 2) / 2) * 2; |
---|
1144 | ap->nrows = (MAX(ap->height / ap->ys - 1, 2) / 2) * 2; |
---|
1145 | ap->xb = (ap->width - ap->xs * ap->ncols) / 2 + ap->xs / 2; |
---|
1146 | ap->yb = (ap->height - ap->ys * ap->nrows) / 2 + ap->ys; |
---|
1147 | for (orient = 0; orient < 2; orient++) { |
---|
1148 | for (i = 0; i < 3; i++) { |
---|
1149 | ap->shape.triangle[orient][i].x = |
---|
1150 | (ap->xs - 2) * triangleUnit[orient][i].x; |
---|
1151 | ap->shape.triangle[orient][i].y = |
---|
1152 | (ap->ys - 2) * triangleUnit[orient][i].y; |
---|
1153 | } |
---|
1154 | /* Avoid array bounds read of triangleUnit */ |
---|
1155 | ap->shape.triangle[orient][3].x = 0; |
---|
1156 | ap->shape.triangle[orient][3].y = 0; |
---|
1157 | } |
---|
1158 | } |
---|
1159 | |
---|
1160 | XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinMiter); |
---|
1161 | MI_CLEARWINDOW(mi); |
---|
1162 | ap->painted = False; |
---|
1163 | |
---|
1164 | if (MI_IS_FULLRANDOM(mi)) { |
---|
1165 | ap->truchet = (Bool) (LRAND() & 1); |
---|
1166 | ap->eyes = (Bool) (LRAND() & 1); |
---|
1167 | ap->sharpturn = (Bool) (LRAND() & 1); |
---|
1168 | } else { |
---|
1169 | ap->truchet = truchet; |
---|
1170 | ap->eyes = eyes; |
---|
1171 | ap->sharpturn = sharpturn; |
---|
1172 | } |
---|
1173 | if (!NRAND(NUMSTIPPLES)) { |
---|
1174 | getTable(mi, (int) (NRAND(NTABLES))); |
---|
1175 | } else |
---|
1176 | getTurk(mi, (int) (NRAND(NUMSTIPPLES - 1))); |
---|
1177 | if (MI_NPIXELS(mi) > 2) |
---|
1178 | for (i = 0; i < (int) ap->ncolors - 1; i++) |
---|
1179 | ap->colors[i] = (unsigned char) (NRAND(MI_NPIXELS(mi)) + |
---|
1180 | i * MI_NPIXELS(mi)) / ((int) (ap->ncolors - 1)); |
---|
1181 | if (ap->ants == NULL) { |
---|
1182 | if ((ap->ants = (antstruct *) malloc(ap->n * sizeof (antstruct))) == |
---|
1183 | NULL) { |
---|
1184 | free_ant(display, ap); |
---|
1185 | return; |
---|
1186 | } |
---|
1187 | } |
---|
1188 | if (ap->tape != NULL) |
---|
1189 | (void) free((void *) ap->tape); |
---|
1190 | if ((ap->tape = (unsigned char *) calloc(ap->ncols * ap->nrows, |
---|
1191 | sizeof (unsigned char))) == NULL) { |
---|
1192 | free_ant(display, ap); |
---|
1193 | return; |
---|
1194 | } |
---|
1195 | if (ap->truchet_state != NULL) |
---|
1196 | (void) free((void *) ap->truchet_state); |
---|
1197 | if ((ap->truchet_state = (unsigned char *) calloc(ap->ncols * ap->nrows, |
---|
1198 | sizeof (unsigned char))) == NULL) { |
---|
1199 | free_ant(display, ap); |
---|
1200 | return; |
---|
1201 | } |
---|
1202 | |
---|
1203 | row = ap->nrows / 2; |
---|
1204 | col = ap->ncols / 2; |
---|
1205 | if (col > 0 && ((ap->neighbors % 2) || ap->neighbors == 12) && (LRAND() & 1)) |
---|
1206 | col--; |
---|
1207 | dir = NRAND(ap->neighbors) * ANGLES / ap->neighbors; |
---|
1208 | ap->init_dir = dir; |
---|
1209 | #ifdef NUMBER_9 |
---|
1210 | if (ap->neighbors == 9 && !((col + row) & 1)) |
---|
1211 | dir = (dir + ANGLES - ANGLES / (ap->neighbors * 2)) % ANGLES; |
---|
1212 | #endif |
---|
1213 | /* Have them all start in the same spot, why not? */ |
---|
1214 | for (i = 0; i < ap->n; i++) { |
---|
1215 | ap->ants[i].col = col; |
---|
1216 | ap->ants[i].row = row; |
---|
1217 | ap->ants[i].direction = dir; |
---|
1218 | ap->ants[i].state = 0; |
---|
1219 | } |
---|
1220 | draw_anant(mi, dir, col, row); |
---|
1221 | } |
---|
1222 | |
---|
1223 | void |
---|
1224 | draw_ant(ModeInfo * mi) |
---|
1225 | { |
---|
1226 | antstruct *anant; |
---|
1227 | statestruct *status; |
---|
1228 | int i, state_pos, tape_pos; |
---|
1229 | unsigned char color; |
---|
1230 | short chg_dir, old_dir; |
---|
1231 | antfarmstruct *ap; |
---|
1232 | |
---|
1233 | if (antfarms == NULL) |
---|
1234 | return; |
---|
1235 | ap = &antfarms[MI_SCREEN(mi)]; |
---|
1236 | if (ap->ants == NULL) |
---|
1237 | return; |
---|
1238 | |
---|
1239 | MI_IS_DRAWN(mi) = True; |
---|
1240 | ap->painted = True; |
---|
1241 | for (i = 0; i < ap->n; i++) { |
---|
1242 | anant = &ap->ants[i]; |
---|
1243 | tape_pos = anant->col + anant->row * ap->ncols; |
---|
1244 | color = ap->tape[tape_pos]; /* read tape */ |
---|
1245 | state_pos = color + anant->state * ap->ncolors; |
---|
1246 | status = &(ap->machine[state_pos]); |
---|
1247 | drawcell(mi, anant->col, anant->row, status->color); |
---|
1248 | ap->tape[tape_pos] = status->color; /* write on tape */ |
---|
1249 | |
---|
1250 | /* Find direction of Bees or Ants. */ |
---|
1251 | /* Translate relative direction to actual direction */ |
---|
1252 | old_dir = anant->direction; |
---|
1253 | chg_dir = (2 * ANGLES - status->direction) % ANGLES; |
---|
1254 | anant->direction = (chg_dir + old_dir) % ANGLES; |
---|
1255 | if (ap->truchet) { |
---|
1256 | int a = 0, b; |
---|
1257 | |
---|
1258 | if (ap->neighbors == 6) { |
---|
1259 | if (ap->sharpturn) { |
---|
1260 | a = (((ANGLES + anant->direction - old_dir) % ANGLES) == 240); |
---|
1261 | /* should be some way of getting rid of the init_dir dependency... */ |
---|
1262 | b = !(ap->init_dir % 120); |
---|
1263 | a = ((a && !b) || (b && !a)); |
---|
1264 | drawtruchet(mi, anant->col, anant->row, status->color, a); |
---|
1265 | } else { |
---|
1266 | a = (old_dir / 60) % 3; |
---|
1267 | b = (anant->direction / 60) % 3; |
---|
1268 | a = (a + b + 1) % 3; |
---|
1269 | drawtruchet(mi, anant->col, anant->row, status->color, a); |
---|
1270 | } |
---|
1271 | } else if (ap->neighbors == 4) { |
---|
1272 | a = old_dir / 180; |
---|
1273 | b = anant->direction / 180; |
---|
1274 | a = ((a && !b) || (b && !a)); |
---|
1275 | drawtruchet(mi, anant->col, anant->row, status->color, a); |
---|
1276 | } else if (ap->neighbors == 3) { |
---|
1277 | if (chg_dir == 240) |
---|
1278 | a = (2 + anant->direction / 120) % 3; |
---|
1279 | else |
---|
1280 | a = (1 + anant->direction / 120) % 3; |
---|
1281 | drawtruchet(mi, anant->col, anant->row, status->color, a); |
---|
1282 | } |
---|
1283 | ap->truchet_state[tape_pos] = a + 1; |
---|
1284 | } |
---|
1285 | anant->state = status->next; |
---|
1286 | |
---|
1287 | /* Allow step first and turn */ |
---|
1288 | old_dir = ((status->direction < ANGLES) ? anant->direction : old_dir); |
---|
1289 | #if DEBUG |
---|
1290 | (void) printf("old_dir %d, col %d, row %d", old_dir, anant->col, anant->row); |
---|
1291 | #endif |
---|
1292 | position_of_neighbor(ap, old_dir, &(anant->col), &(anant->row)); |
---|
1293 | #if DEBUG |
---|
1294 | (void) printf(", ncol %d, nrow %d\n", anant->col, anant->row); |
---|
1295 | #endif |
---|
1296 | draw_anant(mi, anant->direction, anant->col, anant->row); |
---|
1297 | } |
---|
1298 | if (++ap->generation > MI_CYCLES(mi)) { |
---|
1299 | #ifdef STANDALONE |
---|
1300 | erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi)); |
---|
1301 | #endif |
---|
1302 | init_ant(mi); |
---|
1303 | } |
---|
1304 | if (ap->redrawing) { |
---|
1305 | for (i = 0; i < REDRAWSTEP; i++) { |
---|
1306 | if (ap->tape[ap->redrawpos] || |
---|
1307 | (ap->truchet && ap->truchet_state[ap->redrawpos])) { |
---|
1308 | drawcell(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols, |
---|
1309 | ap->tape[ap->redrawpos]); |
---|
1310 | if (ap->truchet) |
---|
1311 | drawtruchet(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols, |
---|
1312 | ap->tape[ap->redrawpos], |
---|
1313 | ap->truchet_state[ap->redrawpos] - 1); |
---|
1314 | } |
---|
1315 | if (++(ap->redrawpos) >= ap->ncols * ap->nrows) { |
---|
1316 | ap->redrawing = 0; |
---|
1317 | break; |
---|
1318 | } |
---|
1319 | } |
---|
1320 | } |
---|
1321 | } |
---|
1322 | |
---|
1323 | void |
---|
1324 | release_ant(ModeInfo * mi) |
---|
1325 | { |
---|
1326 | if (antfarms != NULL) { |
---|
1327 | int screen; |
---|
1328 | |
---|
1329 | for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) |
---|
1330 | free_ant(MI_DISPLAY(mi), &antfarms[screen]); |
---|
1331 | (void) free((void *) antfarms); |
---|
1332 | antfarms = (antfarmstruct *) NULL; |
---|
1333 | } |
---|
1334 | } |
---|
1335 | |
---|
1336 | void |
---|
1337 | refresh_ant(ModeInfo * mi) |
---|
1338 | { |
---|
1339 | antfarmstruct *ap; |
---|
1340 | |
---|
1341 | if (antfarms == NULL) |
---|
1342 | return; |
---|
1343 | ap = &antfarms[MI_SCREEN(mi)]; |
---|
1344 | |
---|
1345 | if (ap->painted) { |
---|
1346 | MI_CLEARWINDOW(mi); |
---|
1347 | ap->redrawing = 1; |
---|
1348 | ap->redrawpos = 0; |
---|
1349 | } |
---|
1350 | } |
---|
1351 | |
---|
1352 | #endif /* MODE_ant */ |
---|