chiark / gitweb /
59effe6d56f7a996be75bcd31ebec15bb36254fa
[sgt-puzzles.git] / net.c
1 /*
2  * net.c: Net game.
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <assert.h>
9 #include <ctype.h>
10 #include <math.h>
11
12 #include "puzzles.h"
13 #include "tree234.h"
14
15 #define PI 3.141592653589793238462643383279502884197169399
16
17 #define MATMUL(xr,yr,m,x,y) do { \
18     float rx, ry, xx = (x), yy = (y), *mat = (m); \
19     rx = mat[0] * xx + mat[2] * yy; \
20     ry = mat[1] * xx + mat[3] * yy; \
21     (xr) = rx; (yr) = ry; \
22 } while (0)
23
24 /* Direction and other bitfields */
25 #define R 0x01
26 #define U 0x02
27 #define L 0x04
28 #define D 0x08
29 #define LOCKED 0x10
30 #define ACTIVE 0x20
31 /* Corner flags go in the barriers array */
32 #define RU 0x10
33 #define UL 0x20
34 #define LD 0x40
35 #define DR 0x80
36
37 /* Rotations: Anticlockwise, Clockwise, Flip, general rotate */
38 #define A(x) ( (((x) & 0x07) << 1) | (((x) & 0x08) >> 3) )
39 #define C(x) ( (((x) & 0x0E) >> 1) | (((x) & 0x01) << 3) )
40 #define F(x) ( (((x) & 0x0C) >> 2) | (((x) & 0x03) << 2) )
41 #define ROT(x, n) ( ((n)&3) == 0 ? (x) : \
42                     ((n)&3) == 1 ? A(x) : \
43                     ((n)&3) == 2 ? F(x) : C(x) )
44
45 /* X and Y displacements */
46 #define X(x) ( (x) == R ? +1 : (x) == L ? -1 : 0 )
47 #define Y(x) ( (x) == D ? +1 : (x) == U ? -1 : 0 )
48
49 /* Bit count */
50 #define COUNT(x) ( (((x) & 0x08) >> 3) + (((x) & 0x04) >> 2) + \
51                    (((x) & 0x02) >> 1) + ((x) & 0x01) )
52
53 #define TILE_SIZE 32
54 #define TILE_BORDER 1
55 #define WINDOW_OFFSET 16
56
57 #define ROTATE_TIME 0.13F
58 #define FLASH_FRAME 0.07F
59
60 /* Transform physical coords to game coords using game_drawstate ds */
61 #define GX(x) (((x) + ds->org_x) % ds->width)
62 #define GY(y) (((y) + ds->org_y) % ds->height)
63 /* ...and game coords to physical coords */
64 #define RX(x) (((x) + ds->width - ds->org_x) % ds->width)
65 #define RY(y) (((y) + ds->height - ds->org_y) % ds->height)
66
67 enum {
68     COL_BACKGROUND,
69     COL_LOCKED,
70     COL_BORDER,
71     COL_WIRE,
72     COL_ENDPOINT,
73     COL_POWERED,
74     COL_BARRIER,
75     NCOLOURS
76 };
77
78 struct game_params {
79     int width;
80     int height;
81     int wrapping;
82     int unique;
83     float barrier_probability;
84 };
85
86 struct game_aux_info {
87     int width, height;
88     unsigned char *tiles;
89 };
90
91 struct game_state {
92     int width, height, wrapping, completed;
93     int last_rotate_x, last_rotate_y, last_rotate_dir;
94     int used_solve, just_used_solve;
95     unsigned char *tiles;
96     unsigned char *barriers;
97 };
98
99 #define OFFSETWH(x2,y2,x1,y1,dir,width,height) \
100     ( (x2) = ((x1) + width + X((dir))) % width, \
101       (y2) = ((y1) + height + Y((dir))) % height)
102
103 #define OFFSET(x2,y2,x1,y1,dir,state) \
104         OFFSETWH(x2,y2,x1,y1,dir,(state)->width,(state)->height)
105
106 #define index(state, a, x, y) ( a[(y) * (state)->width + (x)] )
107 #define tile(state, x, y)     index(state, (state)->tiles, x, y)
108 #define barrier(state, x, y)  index(state, (state)->barriers, x, y)
109
110 struct xyd {
111     int x, y, direction;
112 };
113
114 static int xyd_cmp(const void *av, const void *bv) {
115     const struct xyd *a = (const struct xyd *)av;
116     const struct xyd *b = (const struct xyd *)bv;
117     if (a->x < b->x)
118         return -1;
119     if (a->x > b->x)
120         return +1;
121     if (a->y < b->y)
122         return -1;
123     if (a->y > b->y)
124         return +1;
125     if (a->direction < b->direction)
126         return -1;
127     if (a->direction > b->direction)
128         return +1;
129     return 0;
130 };
131
132 static int xyd_cmp_nc(void *av, void *bv) { return xyd_cmp(av, bv); }
133
134 static struct xyd *new_xyd(int x, int y, int direction)
135 {
136     struct xyd *xyd = snew(struct xyd);
137     xyd->x = x;
138     xyd->y = y;
139     xyd->direction = direction;
140     return xyd;
141 }
142
143 /* ----------------------------------------------------------------------
144  * Manage game parameters.
145  */
146 static game_params *default_params(void)
147 {
148     game_params *ret = snew(game_params);
149
150     ret->width = 5;
151     ret->height = 5;
152     ret->wrapping = FALSE;
153     ret->unique = TRUE;
154     ret->barrier_probability = 0.0;
155
156     return ret;
157 }
158
159 static int game_fetch_preset(int i, char **name, game_params **params)
160 {
161     game_params *ret;
162     char str[80];
163     static const struct { int x, y, wrap; } values[] = {
164         {5, 5, FALSE},
165         {7, 7, FALSE},
166         {9, 9, FALSE},
167         {11, 11, FALSE},
168         {13, 11, FALSE},
169         {5, 5, TRUE},
170         {7, 7, TRUE},
171         {9, 9, TRUE},
172         {11, 11, TRUE},
173         {13, 11, TRUE},
174     };
175
176     if (i < 0 || i >= lenof(values))
177         return FALSE;
178
179     ret = snew(game_params);
180     ret->width = values[i].x;
181     ret->height = values[i].y;
182     ret->wrapping = values[i].wrap;
183     ret->unique = TRUE;
184     ret->barrier_probability = 0.0;
185
186     sprintf(str, "%dx%d%s", ret->width, ret->height,
187             ret->wrapping ? " wrapping" : "");
188
189     *name = dupstr(str);
190     *params = ret;
191     return TRUE;
192 }
193
194 static void free_params(game_params *params)
195 {
196     sfree(params);
197 }
198
199 static game_params *dup_params(game_params *params)
200 {
201     game_params *ret = snew(game_params);
202     *ret = *params;                    /* structure copy */
203     return ret;
204 }
205
206 static void decode_params(game_params *ret, char const *string)
207 {
208     char const *p = string;
209
210     ret->width = atoi(p);
211     while (*p && isdigit((unsigned char)*p)) p++;
212     if (*p == 'x') {
213         p++;
214         ret->height = atoi(p);
215         while (*p && isdigit((unsigned char)*p)) p++;
216     } else {
217         ret->height = ret->width;
218     }
219
220     while (*p) {
221         if (*p == 'w') {
222             p++;
223             ret->wrapping = TRUE;
224         } else if (*p == 'b') {
225             p++;
226             ret->barrier_probability = atof(p);
227             while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++;
228         } else if (*p == 'a') {
229             p++;
230             ret->unique = FALSE;
231         } else
232             p++;                       /* skip any other gunk */
233     }
234 }
235
236 static char *encode_params(game_params *params, int full)
237 {
238     char ret[400];
239     int len;
240
241     len = sprintf(ret, "%dx%d", params->width, params->height);
242     if (params->wrapping)
243         ret[len++] = 'w';
244     if (full && params->barrier_probability)
245         len += sprintf(ret+len, "b%g", params->barrier_probability);
246     if (full && !params->unique)
247         ret[len++] = 'a';
248     assert(len < lenof(ret));
249     ret[len] = '\0';
250
251     return dupstr(ret);
252 }
253
254 static config_item *game_configure(game_params *params)
255 {
256     config_item *ret;
257     char buf[80];
258
259     ret = snewn(6, config_item);
260
261     ret[0].name = "Width";
262     ret[0].type = C_STRING;
263     sprintf(buf, "%d", params->width);
264     ret[0].sval = dupstr(buf);
265     ret[0].ival = 0;
266
267     ret[1].name = "Height";
268     ret[1].type = C_STRING;
269     sprintf(buf, "%d", params->height);
270     ret[1].sval = dupstr(buf);
271     ret[1].ival = 0;
272
273     ret[2].name = "Walls wrap around";
274     ret[2].type = C_BOOLEAN;
275     ret[2].sval = NULL;
276     ret[2].ival = params->wrapping;
277
278     ret[3].name = "Barrier probability";
279     ret[3].type = C_STRING;
280     sprintf(buf, "%g", params->barrier_probability);
281     ret[3].sval = dupstr(buf);
282     ret[3].ival = 0;
283
284     ret[4].name = "Ensure unique solution";
285     ret[4].type = C_BOOLEAN;
286     ret[4].sval = NULL;
287     ret[4].ival = params->unique;
288
289     ret[5].name = NULL;
290     ret[5].type = C_END;
291     ret[5].sval = NULL;
292     ret[5].ival = 0;
293
294     return ret;
295 }
296
297 static game_params *custom_params(config_item *cfg)
298 {
299     game_params *ret = snew(game_params);
300
301     ret->width = atoi(cfg[0].sval);
302     ret->height = atoi(cfg[1].sval);
303     ret->wrapping = cfg[2].ival;
304     ret->barrier_probability = (float)atof(cfg[3].sval);
305     ret->unique = cfg[4].ival;
306
307     return ret;
308 }
309
310 static char *validate_params(game_params *params)
311 {
312     if (params->width <= 0 && params->height <= 0)
313         return "Width and height must both be greater than zero";
314     if (params->width <= 0)
315         return "Width must be greater than zero";
316     if (params->height <= 0)
317         return "Height must be greater than zero";
318     if (params->width <= 1 && params->height <= 1)
319         return "At least one of width and height must be greater than one";
320     if (params->barrier_probability < 0)
321         return "Barrier probability may not be negative";
322     if (params->barrier_probability > 1)
323         return "Barrier probability may not be greater than 1";
324
325     /*
326      * Specifying either grid dimension as 2 in a wrapping puzzle
327      * makes it actually impossible to ensure a unique puzzle
328      * solution.
329      * 
330      * Proof:
331      * 
332      * Without loss of generality, let us assume the puzzle _width_
333      * is 2, so we can conveniently discuss rows without having to
334      * say `rows/columns' all the time. (The height may be 2 as
335      * well, but that doesn't matter.)
336      * 
337      * In each row, there are two edges between tiles: the inner
338      * edge (running down the centre of the grid) and the outer
339      * edge (the identified left and right edges of the grid).
340      * 
341      * Lemma: In any valid 2xn puzzle there must be at least one
342      * row in which _exactly one_ of the inner edge and outer edge
343      * is connected.
344      * 
345      *   Proof: No row can have _both_ inner and outer edges
346      *   connected, because this would yield a loop. So the only
347      *   other way to falsify the lemma is for every row to have
348      *   _neither_ the inner nor outer edge connected. But this
349      *   means there is no connection at all between the left and
350      *   right columns of the puzzle, so there are two disjoint
351      *   subgraphs, which is also disallowed. []
352      * 
353      * Given such a row, it is always possible to make the
354      * disconnected edge connected and the connected edge
355      * disconnected without changing the state of any other edge.
356      * (This is easily seen by case analysis on the various tiles:
357      * left-pointing and right-pointing endpoints can be exchanged,
358      * likewise T-pieces, and a corner piece can select its
359      * horizontal connectivity independently of its vertical.) This
360      * yields a distinct valid solution.
361      * 
362      * Thus, for _every_ row in which exactly one of the inner and
363      * outer edge is connected, there are two valid states for that
364      * row, and hence the total number of solutions of the puzzle
365      * is at least 2^(number of such rows), and in particular is at
366      * least 2 since there must be at least one such row. []
367      */
368     if (params->unique && params->wrapping &&
369         (params->width == 2 || params->height == 2))
370         return "No wrapping puzzle with a width or height of 2 can have"
371         " a unique solution";
372
373     return NULL;
374 }
375
376 /* ----------------------------------------------------------------------
377  * Solver used to assure solution uniqueness during generation. 
378  */
379
380 /*
381  * Test cases I used while debugging all this were
382  * 
383  *   ./net --generate 1 13x11w#12300
384  * which expands under the non-unique grid generation rules to
385  *   13x11w:5eaade1bd222664436d5e2965c12656b1129dd825219e3274d558d5eb2dab5da18898e571d5a2987be79746bd95726c597447d6da96188c513add829da7681da954db113d3cd244
386  * and has two ambiguous areas.
387  * 
388  * An even better one is
389  *   13x11w#507896411361192
390  * which expands to
391  *   13x11w:b7125b1aec598eb31bd58d82572bc11494e5dee4e8db2bdd29b88d41a16bdd996d2996ddec8c83741a1e8674e78328ba71737b8894a9271b1cd1399453d1952e43951d9b712822e
392  * and has an ambiguous area _and_ a situation where loop avoidance
393  * is a necessary deductive technique.
394  * 
395  * Then there's
396  *   48x25w#820543338195187
397  * becoming
398  *   48x25w:255989d14cdd185deaa753a93821a12edc1ab97943ac127e2685d7b8b3c48861b2192416139212b316eddd35de43714ebc7628d753db32e596284d9ec52c5a7dc1b4c811a655117d16dc28921b2b4161352cab1d89d18bc836b8b891d55ea4622a1251861b5bc9a8aa3e5bcd745c95229ca6c3b5e21d5832d397e917325793d7eb442dc351b2db2a52ba8e1651642275842d8871d5534aabc6d5b741aaa2d48ed2a7dbbb3151ddb49d5b9a7ed1ab98ee75d613d656dbba347bc514c84556b43a9bc65a3256ead792488b862a9d2a8a39b4255a4949ed7dbd79443292521265896b4399c95ede89d7c8c797a6a57791a849adea489359a158aa12e5dacce862b8333b7ebea7d344d1a3c53198864b73a9dedde7b663abb1b539e1e8853b1b7edb14a2a17ebaae4dbe63598a2e7e9a2dbdad415bc1d8cb88cbab5a8c82925732cd282e641ea3bd7d2c6e776de9117a26be86deb7c82c89524b122cb9397cd1acd2284e744ea62b9279bae85479ababe315c3ac29c431333395b24e6a1e3c43a2da42d4dce84aadd5b154aea555eaddcbd6e527d228c19388d9b424d94214555a7edbdeebe569d4a56dc51a86bd9963e377bb74752bd5eaa5761ba545e297b62a1bda46ab4aee423ad6c661311783cc18786d4289236563cb4a75ec67d481c14814994464cd1b87396dee63e5ab6e952cc584baa1d4c47cb557ec84dbb63d487c8728118673a166846dd3a4ebc23d6cb9c5827d96b4556e91899db32b517eda815ae271a8911bd745447121dc8d321557bc2a435ebec1bbac35b1a291669451174e6aa2218a4a9c5a6ca31ebc45d84e3a82c121e9ced7d55e9a
399  * which has a spot (far right) where slightly more complex loop
400  * avoidance is required.
401  */
402
403 static int dsf_canonify(int *dsf, int val)
404 {
405     int v2 = val;
406
407     while (dsf[val] != val)
408         val = dsf[val];
409
410     while (v2 != val) {
411         int tmp = dsf[v2];
412         dsf[v2] = val;
413         v2 = tmp;
414     }
415
416     return val;
417 }
418
419 static void dsf_merge(int *dsf, int v1, int v2)
420 {
421     v1 = dsf_canonify(dsf, v1);
422     v2 = dsf_canonify(dsf, v2);
423     dsf[v2] = v1;
424 }
425
426 struct todo {
427     unsigned char *marked;
428     int *buffer;
429     int buflen;
430     int head, tail;
431 };
432
433 static struct todo *todo_new(int maxsize)
434 {
435     struct todo *todo = snew(struct todo);
436     todo->marked = snewn(maxsize, unsigned char);
437     memset(todo->marked, 0, maxsize);
438     todo->buflen = maxsize + 1;
439     todo->buffer = snewn(todo->buflen, int);
440     todo->head = todo->tail = 0;
441     return todo;
442 }
443
444 static void todo_free(struct todo *todo)
445 {
446     sfree(todo->marked);
447     sfree(todo->buffer);
448     sfree(todo);
449 }
450
451 static void todo_add(struct todo *todo, int index)
452 {
453     if (todo->marked[index])
454         return;                        /* already on the list */
455     todo->marked[index] = TRUE;
456     todo->buffer[todo->tail++] = index;
457     if (todo->tail == todo->buflen)
458         todo->tail = 0;
459 }
460
461 static int todo_get(struct todo *todo) {
462     int ret;
463
464     if (todo->head == todo->tail)
465         return -1;                     /* list is empty */
466     ret = todo->buffer[todo->head++];
467     if (todo->head == todo->buflen)
468         todo->head = 0;
469     todo->marked[ret] = FALSE;
470
471     return ret;
472 }
473
474 static int net_solver(int w, int h, unsigned char *tiles,
475                       unsigned char *barriers, int wrapping)
476 {
477     unsigned char *tilestate;
478     unsigned char *edgestate;
479     int *deadends;
480     int *equivalence;
481     struct todo *todo;
482     int i, j, x, y;
483     int area;
484     int done_something;
485
486     /*
487      * Set up the solver's data structures.
488      */
489     
490     /*
491      * tilestate stores the possible orientations of each tile.
492      * There are up to four of these, so we'll index the array in
493      * fours. tilestate[(y * w + x) * 4] and its three successive
494      * members give the possible orientations, clearing to 255 from
495      * the end as things are ruled out.
496      * 
497      * In this loop we also count up the area of the grid (which is
498      * not _necessarily_ equal to w*h, because there might be one
499      * or more blank squares present. This will never happen in a
500      * grid generated _by_ this program, but it's worth keeping the
501      * solver as general as possible.)
502      */
503     tilestate = snewn(w * h * 4, unsigned char);
504     area = 0;
505     for (i = 0; i < w*h; i++) {
506         tilestate[i * 4] = tiles[i] & 0xF;
507         for (j = 1; j < 4; j++) {
508             if (tilestate[i * 4 + j - 1] == 255 ||
509                 A(tilestate[i * 4 + j - 1]) == tilestate[i * 4])
510                 tilestate[i * 4 + j] = 255;
511             else
512                 tilestate[i * 4 + j] = A(tilestate[i * 4 + j - 1]);
513         }
514         if (tiles[i] != 0)
515             area++;
516     }
517
518     /*
519      * edgestate stores the known state of each edge. It is 0 for
520      * unknown, 1 for open (connected) and 2 for closed (not
521      * connected).
522      * 
523      * In principle we need only worry about each edge once each,
524      * but in fact it's easier to track each edge twice so that we
525      * can reference it from either side conveniently. Also I'm
526      * going to allocate _five_ bytes per tile, rather than the
527      * obvious four, so that I can index edgestate[(y*w+x) * 5 + d]
528      * where d is 1,2,4,8 and they never overlap.
529      */
530     edgestate = snewn((w * h - 1) * 5 + 9, unsigned char);
531     memset(edgestate, 0, (w * h - 1) * 5 + 9);
532
533     /*
534      * deadends tracks which edges have dead ends on them. It is
535      * indexed by tile and direction: deadends[(y*w+x) * 5 + d]
536      * tells you whether heading out of tile (x,y) in direction d
537      * can reach a limited amount of the grid. Values are area+1
538      * (no dead end known) or less than that (can reach _at most_
539      * this many other tiles by heading this way out of this tile).
540      */
541     deadends = snewn((w * h - 1) * 5 + 9, int);
542     for (i = 0; i < (w * h - 1) * 5 + 9; i++)
543         deadends[i] = area+1;
544
545     /*
546      * equivalence tracks which sets of tiles are known to be
547      * connected to one another, so we can avoid creating loops by
548      * linking together tiles which are already linked through
549      * another route.
550      * 
551      * This is a disjoint set forest structure: equivalence[i]
552      * contains the index of another member of the equivalence
553      * class containing i, or contains i itself for precisely one
554      * member in each such class. To find a representative member
555      * of the equivalence class containing i, you keep replacing i
556      * with equivalence[i] until it stops changing; then you go
557      * _back_ along the same path and point everything on it
558      * directly at the representative member so as to speed up
559      * future searches. Then you test equivalence between tiles by
560      * finding the representative of each tile and seeing if
561      * they're the same; and you create new equivalence (merge
562      * classes) by finding the representative of each tile and
563      * setting equivalence[one]=the_other.
564      */
565     equivalence = snewn(w * h, int);
566     for (i = 0; i < w*h; i++)
567         equivalence[i] = i;            /* initially all distinct */
568
569     /*
570      * On a non-wrapping grid, we instantly know that all the edges
571      * round the edge are closed.
572      */
573     if (!wrapping) {
574         for (i = 0; i < w; i++) {
575             edgestate[i * 5 + 2] = edgestate[((h-1) * w + i) * 5 + 8] = 2;
576         }
577         for (i = 0; i < h; i++) {
578             edgestate[(i * w + w-1) * 5 + 1] = edgestate[(i * w) * 5 + 4] = 2;
579         }
580     }
581
582     /*
583      * If we have barriers available, we can mark those edges as
584      * closed too.
585      */
586     if (barriers) {
587         for (y = 0; y < h; y++) for (x = 0; x < w; x++) {
588             int d;
589             for (d = 1; d <= 8; d += d) {
590                 if (barriers[y*w+x] & d) {
591                     int x2, y2;
592                     /*
593                      * In principle the barrier list should already
594                      * contain each barrier from each side, but
595                      * let's not take chances with our internal
596                      * consistency.
597                      */
598                     OFFSETWH(x2, y2, x, y, d, w, h);
599                     edgestate[(y*w+x) * 5 + d] = 2;
600                     edgestate[(y2*w+x2) * 5 + F(d)] = 2;
601                 }
602             }
603         }
604     }
605
606     /*
607      * Since most deductions made by this solver are local (the
608      * exception is loop avoidance, where joining two tiles
609      * together on one side of the grid can theoretically permit a
610      * fresh deduction on the other), we can address the scaling
611      * problem inherent in iterating repeatedly over the entire
612      * grid by instead working with a to-do list.
613      */
614     todo = todo_new(w * h);
615
616     /*
617      * Main deductive loop.
618      */
619     done_something = TRUE;             /* prevent instant termination! */
620     while (1) {
621         int index;
622
623         /*
624          * Take a tile index off the todo list and process it.
625          */
626         index = todo_get(todo);
627         if (index == -1) {
628             /*
629              * If we have run out of immediate things to do, we
630              * have no choice but to scan the whole grid for
631              * longer-range things we've missed. Hence, I now add
632              * every square on the grid back on to the to-do list.
633              * I also set `done_something' to FALSE at this point;
634              * if we later come back here and find it still FALSE,
635              * we will know we've scanned the entire grid without
636              * finding anything new to do, and we can terminate.
637              */
638             if (!done_something)
639                 break;
640             for (i = 0; i < w*h; i++)
641                 todo_add(todo, i);
642             done_something = FALSE;
643
644             index = todo_get(todo);
645         }
646
647         y = index / w;
648         x = index % w;
649         {
650             int d, ourclass = dsf_canonify(equivalence, y*w+x);
651             int deadendmax[9];
652
653             deadendmax[1] = deadendmax[2] = deadendmax[4] = deadendmax[8] = 0;
654
655             for (i = j = 0; i < 4 && tilestate[(y*w+x) * 4 + i] != 255; i++) {
656                 int valid;
657                 int nnondeadends, nondeadends[4], deadendtotal;
658                 int nequiv, equiv[5];
659                 int val = tilestate[(y*w+x) * 4 + i];
660
661                 valid = TRUE;
662                 nnondeadends = deadendtotal = 0;
663                 equiv[0] = ourclass;
664                 nequiv = 1;
665                 for (d = 1; d <= 8; d += d) {
666                     /*
667                      * Immediately rule out this orientation if it
668                      * conflicts with any known edge.
669                      */
670                     if ((edgestate[(y*w+x) * 5 + d] == 1 && !(val & d)) ||
671                         (edgestate[(y*w+x) * 5 + d] == 2 && (val & d)))
672                         valid = FALSE;
673
674                     if (val & d) {
675                         /*
676                          * Count up the dead-end statistics.
677                          */
678                         if (deadends[(y*w+x) * 5 + d] <= area) {
679                             deadendtotal += deadends[(y*w+x) * 5 + d];
680                         } else {
681                             nondeadends[nnondeadends++] = d;
682                         }
683
684                         /*
685                          * Ensure we aren't linking to any tiles,
686                          * through edges not already known to be
687                          * open, which create a loop.
688                          */
689                         if (edgestate[(y*w+x) * 5 + d] == 0) {
690                             int c, k, x2, y2;
691                             
692                             OFFSETWH(x2, y2, x, y, d, w, h);
693                             c = dsf_canonify(equivalence, y2*w+x2);
694                             for (k = 0; k < nequiv; k++)
695                                 if (c == equiv[k])
696                                     break;
697                             if (k == nequiv)
698                                 equiv[nequiv++] = c;
699                             else
700                                 valid = FALSE;
701                         }
702                     }
703                 }
704
705                 if (nnondeadends == 0) {
706                     /*
707                      * If this orientation links together dead-ends
708                      * with a total area of less than the entire
709                      * grid, it is invalid.
710                      *
711                      * (We add 1 to deadendtotal because of the
712                      * tile itself, of course; one tile linking
713                      * dead ends of size 2 and 3 forms a subnetwork
714                      * with a total area of 6, not 5.)
715                      */
716                     if (deadendtotal > 0 && deadendtotal+1 < area)
717                         valid = FALSE;
718                 } else if (nnondeadends == 1) {
719                     /*
720                      * If this orientation links together one or
721                      * more dead-ends with precisely one
722                      * non-dead-end, then we may have to mark that
723                      * non-dead-end as a dead end going the other
724                      * way. However, it depends on whether all
725                      * other orientations share the same property.
726                      */
727                     deadendtotal++;
728                     if (deadendmax[nondeadends[0]] < deadendtotal)
729                         deadendmax[nondeadends[0]] = deadendtotal;
730                 } else {
731                     /*
732                      * If this orientation links together two or
733                      * more non-dead-ends, then we can rule out the
734                      * possibility of putting in new dead-end
735                      * markings in those directions.
736                      */
737                     int k;
738                     for (k = 0; k < nnondeadends; k++)
739                         deadendmax[nondeadends[k]] = area+1;
740                 }
741
742                 if (valid)
743                     tilestate[(y*w+x) * 4 + j++] = val;
744 #ifdef SOLVER_DIAGNOSTICS
745                 else
746                     printf("ruling out orientation %x at %d,%d\n", val, x, y);
747 #endif
748             }
749
750             assert(j > 0);             /* we can't lose _all_ possibilities! */
751
752             if (j < i) {
753                 done_something = TRUE;
754
755                 /*
756                  * We have ruled out at least one tile orientation.
757                  * Make sure the rest are blanked.
758                  */
759                 while (j < 4)
760                     tilestate[(y*w+x) * 4 + j++] = 255;
761             }
762
763             /*
764              * Now go through the tile orientations again and see
765              * if we've deduced anything new about any edges.
766              */
767             {
768                 int a, o;
769                 a = 0xF; o = 0;
770
771                 for (i = 0; i < 4 && tilestate[(y*w+x) * 4 + i] != 255; i++) {
772                     a &= tilestate[(y*w+x) * 4 + i];
773                     o |= tilestate[(y*w+x) * 4 + i];
774                 }
775                 for (d = 1; d <= 8; d += d)
776                     if (edgestate[(y*w+x) * 5 + d] == 0) {
777                         int x2, y2, d2;
778                         OFFSETWH(x2, y2, x, y, d, w, h);
779                         d2 = F(d);
780                         if (a & d) {
781                             /* This edge is open in all orientations. */
782 #ifdef SOLVER_DIAGNOSTICS
783                             printf("marking edge %d,%d:%d open\n", x, y, d);
784 #endif
785                             edgestate[(y*w+x) * 5 + d] = 1;
786                             edgestate[(y2*w+x2) * 5 + d2] = 1;
787                             dsf_merge(equivalence, y*w+x, y2*w+x2);
788                             done_something = TRUE;
789                             todo_add(todo, y2*w+x2);
790                         } else if (!(o & d)) {
791                             /* This edge is closed in all orientations. */
792 #ifdef SOLVER_DIAGNOSTICS
793                             printf("marking edge %d,%d:%d closed\n", x, y, d);
794 #endif
795                             edgestate[(y*w+x) * 5 + d] = 2;
796                             edgestate[(y2*w+x2) * 5 + d2] = 2;
797                             done_something = TRUE;
798                             todo_add(todo, y2*w+x2);
799                         }
800                     }
801
802             }
803
804             /*
805              * Now check the dead-end markers and see if any of
806              * them has lowered from the real ones.
807              */
808             for (d = 1; d <= 8; d += d) {
809                 int x2, y2, d2;
810                 OFFSETWH(x2, y2, x, y, d, w, h);
811                 d2 = F(d);
812                 if (deadendmax[d] > 0 &&
813                     deadends[(y2*w+x2) * 5 + d2] > deadendmax[d]) {
814 #ifdef SOLVER_DIAGNOSTICS
815                     printf("setting dead end value %d,%d:%d to %d\n",
816                            x2, y2, d2, deadendmax[d]);
817 #endif
818                     deadends[(y2*w+x2) * 5 + d2] = deadendmax[d];
819                     done_something = TRUE;
820                     todo_add(todo, y2*w+x2);
821                 }
822             }
823
824         }
825     }
826
827     /*
828      * Mark all completely determined tiles as locked.
829      */
830     j = TRUE;
831     for (i = 0; i < w*h; i++) {
832         if (tilestate[i * 4 + 1] == 255) {
833             assert(tilestate[i * 4 + 0] != 255);
834             tiles[i] = tilestate[i * 4] | LOCKED;
835         } else {
836             tiles[i] &= ~LOCKED;
837             j = FALSE;
838         }
839     }
840
841     /*
842      * Free up working space.
843      */
844     todo_free(todo);
845     sfree(tilestate);
846     sfree(edgestate);
847     sfree(deadends);
848     sfree(equivalence);
849
850     return j;
851 }
852
853 /* ----------------------------------------------------------------------
854  * Randomly select a new game description.
855  */
856
857 /*
858  * Function to randomly perturb an ambiguous section in a grid, to
859  * attempt to ensure unique solvability.
860  */
861 static void perturb(int w, int h, unsigned char *tiles, int wrapping,
862                     random_state *rs, int startx, int starty, int startd)
863 {
864     struct xyd *perimeter, *perim2, *loop[2], looppos[2];
865     int nperim, perimsize, nloop[2], loopsize[2];
866     int x, y, d, i;
867
868     /*
869      * We know that the tile at (startx,starty) is part of an
870      * ambiguous section, and we also know that its neighbour in
871      * direction startd is fully specified. We begin by tracing all
872      * the way round the ambiguous area.
873      */
874     nperim = perimsize = 0;
875     perimeter = NULL;
876     x = startx;
877     y = starty;
878     d = startd;
879 #ifdef PERTURB_DIAGNOSTICS
880     printf("perturb %d,%d:%d\n", x, y, d);
881 #endif
882     do {
883         int x2, y2, d2;
884
885         if (nperim >= perimsize) {
886             perimsize = perimsize * 3 / 2 + 32;
887             perimeter = sresize(perimeter, perimsize, struct xyd);
888         }
889         perimeter[nperim].x = x;
890         perimeter[nperim].y = y;
891         perimeter[nperim].direction = d;
892         nperim++;
893 #ifdef PERTURB_DIAGNOSTICS
894         printf("perimeter: %d,%d:%d\n", x, y, d);
895 #endif
896
897         /*
898          * First, see if we can simply turn left from where we are
899          * and find another locked square.
900          */
901         d2 = A(d);
902         OFFSETWH(x2, y2, x, y, d2, w, h);
903         if ((!wrapping && (abs(x2-x) > 1 || abs(y2-y) > 1)) ||
904             (tiles[y2*w+x2] & LOCKED)) {
905             d = d2;
906         } else {
907             /*
908              * Failing that, step left into the new square and look
909              * in front of us.
910              */
911             x = x2;
912             y = y2;
913             OFFSETWH(x2, y2, x, y, d, w, h);
914             if ((wrapping || (abs(x2-x) <= 1 && abs(y2-y) <= 1)) &&
915                 !(tiles[y2*w+x2] & LOCKED)) {
916                 /*
917                  * And failing _that_, we're going to have to step
918                  * forward into _that_ square and look right at the
919                  * same locked square as we started with.
920                  */
921                 x = x2;
922                 y = y2;
923                 d = C(d);
924             }
925         }
926
927     } while (x != startx || y != starty || d != startd);
928
929     /*
930      * Our technique for perturbing this ambiguous area is to
931      * search round its edge for a join we can make: that is, an
932      * edge on the perimeter which is (a) not currently connected,
933      * and (b) connecting it would not yield a full cross on either
934      * side. Then we make that join, search round the network to
935      * find the loop thus constructed, and sever the loop at a
936      * randomly selected other point.
937      */
938     perim2 = snewn(nperim, struct xyd);
939     memcpy(perim2, perimeter, nperim * sizeof(struct xyd));
940     /* Shuffle the perimeter, so as to search it without directional bias. */
941     for (i = nperim; --i ;) {
942         int j = random_upto(rs, i+1);
943         struct xyd t;
944
945         t = perim2[j];
946         perim2[j] = perim2[i];
947         perim2[i] = t;
948     }
949     for (i = 0; i < nperim; i++) {
950         int x2, y2;
951
952         x = perim2[i].x;
953         y = perim2[i].y;
954         d = perim2[i].direction;
955
956         OFFSETWH(x2, y2, x, y, d, w, h);
957         if (!wrapping && (abs(x2-x) > 1 || abs(y2-y) > 1))
958             continue;            /* can't link across non-wrapping border */
959         if (tiles[y*w+x] & d)
960             continue;                  /* already linked in this direction! */
961         if (((tiles[y*w+x] | d) & 15) == 15)
962             continue;                  /* can't turn this tile into a cross */
963         if (((tiles[y2*w+x2] | F(d)) & 15) == 15)
964             continue;                  /* can't turn other tile into a cross */
965
966         /*
967          * We've found the point at which we're going to make a new
968          * link.
969          */
970 #ifdef PERTURB_DIAGNOSTICS      
971         printf("linking %d,%d:%d\n", x, y, d);
972 #endif
973         tiles[y*w+x] |= d;
974         tiles[y2*w+x2] |= F(d);
975
976         break;
977     }
978
979     if (i == nperim)
980         return;                        /* nothing we can do! */
981
982     /*
983      * Now we've constructed a new link, we need to find the entire
984      * loop of which it is a part.
985      * 
986      * In principle, this involves doing a complete search round
987      * the network. However, I anticipate that in the vast majority
988      * of cases the loop will be quite small, so what I'm going to
989      * do is make _two_ searches round the network in parallel, one
990      * keeping its metaphorical hand on the left-hand wall while
991      * the other keeps its hand on the right. As soon as one of
992      * them gets back to its starting point, I abandon the other.
993      */
994     for (i = 0; i < 2; i++) {
995         loopsize[i] = nloop[i] = 0;
996         loop[i] = NULL;
997         looppos[i].x = x;
998         looppos[i].y = y;
999         looppos[i].direction = d;
1000     }
1001     while (1) {
1002         for (i = 0; i < 2; i++) {
1003             int x2, y2, j;
1004
1005             x = looppos[i].x;
1006             y = looppos[i].y;
1007             d = looppos[i].direction;
1008
1009             OFFSETWH(x2, y2, x, y, d, w, h);
1010
1011             /*
1012              * Add this path segment to the loop, unless it exactly
1013              * reverses the previous one on the loop in which case
1014              * we take it away again.
1015              */
1016 #ifdef PERTURB_DIAGNOSTICS
1017             printf("looppos[%d] = %d,%d:%d\n", i, x, y, d);
1018 #endif
1019             if (nloop[i] > 0 &&
1020                 loop[i][nloop[i]-1].x == x2 &&
1021                 loop[i][nloop[i]-1].y == y2 &&
1022                 loop[i][nloop[i]-1].direction == F(d)) {
1023 #ifdef PERTURB_DIAGNOSTICS
1024                 printf("removing path segment %d,%d:%d from loop[%d]\n",
1025                        x2, y2, F(d), i);
1026 #endif
1027                 nloop[i]--;
1028             } else {
1029                 if (nloop[i] >= loopsize[i]) {
1030                     loopsize[i] = loopsize[i] * 3 / 2 + 32;
1031                     loop[i] = sresize(loop[i], loopsize[i], struct xyd);
1032                 }
1033 #ifdef PERTURB_DIAGNOSTICS
1034                 printf("adding path segment %d,%d:%d to loop[%d]\n",
1035                        x, y, d, i);
1036 #endif
1037                 loop[i][nloop[i]++] = looppos[i];
1038             }
1039
1040 #ifdef PERTURB_DIAGNOSTICS
1041             printf("tile at new location is %x\n", tiles[y2*w+x2] & 0xF);
1042 #endif
1043             d = F(d);
1044             for (j = 0; j < 4; j++) {
1045                 if (i == 0)
1046                     d = A(d);
1047                 else
1048                     d = C(d);
1049 #ifdef PERTURB_DIAGNOSTICS
1050                 printf("trying dir %d\n", d);
1051 #endif
1052                 if (tiles[y2*w+x2] & d) {
1053                     looppos[i].x = x2;
1054                     looppos[i].y = y2;
1055                     looppos[i].direction = d;
1056                     break;
1057                 }
1058             }
1059
1060             assert(j < 4);
1061             assert(nloop[i] > 0);
1062
1063             if (looppos[i].x == loop[i][0].x &&
1064                 looppos[i].y == loop[i][0].y &&
1065                 looppos[i].direction == loop[i][0].direction) {
1066 #ifdef PERTURB_DIAGNOSTICS
1067                 printf("loop %d finished tracking\n", i);
1068 #endif
1069
1070                 /*
1071                  * Having found our loop, we now sever it at a
1072                  * randomly chosen point - absolutely any will do -
1073                  * which is not the one we joined it at to begin
1074                  * with. Conveniently, the one we joined it at is
1075                  * loop[i][0], so we just avoid that one.
1076                  */
1077                 j = random_upto(rs, nloop[i]-1) + 1;
1078                 x = loop[i][j].x;
1079                 y = loop[i][j].y;
1080                 d = loop[i][j].direction;
1081                 OFFSETWH(x2, y2, x, y, d, w, h);
1082                 tiles[y*w+x] &= ~d;
1083                 tiles[y2*w+x2] &= ~F(d);
1084
1085                 break;
1086             }
1087         }
1088         if (i < 2)
1089             break;
1090     }
1091     sfree(loop[0]);
1092     sfree(loop[1]);
1093
1094     /*
1095      * Finally, we must mark the entire disputed section as locked,
1096      * to prevent the perturb function being called on it multiple
1097      * times.
1098      * 
1099      * To do this, we _sort_ the perimeter of the area. The
1100      * existing xyd_cmp function will arrange things into columns
1101      * for us, in such a way that each column has the edges in
1102      * vertical order. Then we can work down each column and fill
1103      * in all the squares between an up edge and a down edge.
1104      */
1105     qsort(perimeter, nperim, sizeof(struct xyd), xyd_cmp);
1106     x = y = -1;
1107     for (i = 0; i <= nperim; i++) {
1108         if (i == nperim || perimeter[i].x > x) {
1109             /*
1110              * Fill in everything from the last Up edge to the
1111              * bottom of the grid, if necessary.
1112              */
1113             if (x != -1) {
1114                 while (y < h) {
1115 #ifdef PERTURB_DIAGNOSTICS
1116                     printf("resolved: locking tile %d,%d\n", x, y);
1117 #endif
1118                     tiles[y * w + x] |= LOCKED;
1119                     y++;
1120                 }
1121                 x = y = -1;
1122             }
1123
1124             if (i == nperim)
1125                 break;
1126
1127             x = perimeter[i].x;
1128             y = 0;
1129         }
1130
1131         if (perimeter[i].direction == U) {
1132             x = perimeter[i].x;
1133             y = perimeter[i].y;
1134         } else if (perimeter[i].direction == D) {
1135             /*
1136              * Fill in everything from the last Up edge to here.
1137              */
1138             assert(x == perimeter[i].x && y <= perimeter[i].y);
1139             while (y <= perimeter[i].y) {
1140 #ifdef PERTURB_DIAGNOSTICS
1141                 printf("resolved: locking tile %d,%d\n", x, y);
1142 #endif
1143                 tiles[y * w + x] |= LOCKED;
1144                 y++;
1145             }
1146             x = y = -1;
1147         }
1148     }
1149
1150     sfree(perimeter);
1151 }
1152
1153 static char *new_game_desc(game_params *params, random_state *rs,
1154                            game_aux_info **aux)
1155 {
1156     tree234 *possibilities, *barriertree;
1157     int w, h, x, y, cx, cy, nbarriers;
1158     unsigned char *tiles, *barriers;
1159     char *desc, *p;
1160
1161     w = params->width;
1162     h = params->height;
1163
1164     cx = w / 2;
1165     cy = h / 2;
1166
1167     tiles = snewn(w * h, unsigned char);
1168     barriers = snewn(w * h, unsigned char);
1169
1170     begin_generation:
1171
1172     memset(tiles, 0, w * h);
1173     memset(barriers, 0, w * h);
1174
1175     /*
1176      * Construct the unshuffled grid.
1177      * 
1178      * To do this, we simply start at the centre point, repeatedly
1179      * choose a random possibility out of the available ways to
1180      * extend a used square into an unused one, and do it. After
1181      * extending the third line out of a square, we remove the
1182      * fourth from the possibilities list to avoid any full-cross
1183      * squares (which would make the game too easy because they
1184      * only have one orientation).
1185      * 
1186      * The slightly worrying thing is the avoidance of full-cross
1187      * squares. Can this cause our unsophisticated construction
1188      * algorithm to paint itself into a corner, by getting into a
1189      * situation where there are some unreached squares and the
1190      * only way to reach any of them is to extend a T-piece into a
1191      * full cross?
1192      * 
1193      * Answer: no it can't, and here's a proof.
1194      * 
1195      * Any contiguous group of such unreachable squares must be
1196      * surrounded on _all_ sides by T-pieces pointing away from the
1197      * group. (If not, then there is a square which can be extended
1198      * into one of the `unreachable' ones, and so it wasn't
1199      * unreachable after all.) In particular, this implies that
1200      * each contiguous group of unreachable squares must be
1201      * rectangular in shape (any deviation from that yields a
1202      * non-T-piece next to an `unreachable' square).
1203      * 
1204      * So we have a rectangle of unreachable squares, with T-pieces
1205      * forming a solid border around the rectangle. The corners of
1206      * that border must be connected (since every tile connects all
1207      * the lines arriving in it), and therefore the border must
1208      * form a closed loop around the rectangle.
1209      * 
1210      * But this can't have happened in the first place, since we
1211      * _know_ we've avoided creating closed loops! Hence, no such
1212      * situation can ever arise, and the naive grid construction
1213      * algorithm will guaranteeably result in a complete grid
1214      * containing no unreached squares, no full crosses _and_ no
1215      * closed loops. []
1216      */
1217     possibilities = newtree234(xyd_cmp_nc);
1218
1219     if (cx+1 < w)
1220         add234(possibilities, new_xyd(cx, cy, R));
1221     if (cy-1 >= 0)
1222         add234(possibilities, new_xyd(cx, cy, U));
1223     if (cx-1 >= 0)
1224         add234(possibilities, new_xyd(cx, cy, L));
1225     if (cy+1 < h)
1226         add234(possibilities, new_xyd(cx, cy, D));
1227
1228     while (count234(possibilities) > 0) {
1229         int i;
1230         struct xyd *xyd;
1231         int x1, y1, d1, x2, y2, d2, d;
1232
1233         /*
1234          * Extract a randomly chosen possibility from the list.
1235          */
1236         i = random_upto(rs, count234(possibilities));
1237         xyd = delpos234(possibilities, i);
1238         x1 = xyd->x;
1239         y1 = xyd->y;
1240         d1 = xyd->direction;
1241         sfree(xyd);
1242
1243         OFFSET(x2, y2, x1, y1, d1, params);
1244         d2 = F(d1);
1245 #ifdef DEBUG
1246         printf("picked (%d,%d,%c) <-> (%d,%d,%c)\n",
1247                x1, y1, "0RU3L567D9abcdef"[d1], x2, y2, "0RU3L567D9abcdef"[d2]);
1248 #endif
1249
1250         /*
1251          * Make the connection. (We should be moving to an as yet
1252          * unused tile.)
1253          */
1254         index(params, tiles, x1, y1) |= d1;
1255         assert(index(params, tiles, x2, y2) == 0);
1256         index(params, tiles, x2, y2) |= d2;
1257
1258         /*
1259          * If we have created a T-piece, remove its last
1260          * possibility.
1261          */
1262         if (COUNT(index(params, tiles, x1, y1)) == 3) {
1263             struct xyd xyd1, *xydp;
1264
1265             xyd1.x = x1;
1266             xyd1.y = y1;
1267             xyd1.direction = 0x0F ^ index(params, tiles, x1, y1);
1268
1269             xydp = find234(possibilities, &xyd1, NULL);
1270
1271             if (xydp) {
1272 #ifdef DEBUG
1273                 printf("T-piece; removing (%d,%d,%c)\n",
1274                        xydp->x, xydp->y, "0RU3L567D9abcdef"[xydp->direction]);
1275 #endif
1276                 del234(possibilities, xydp);
1277                 sfree(xydp);
1278             }
1279         }
1280
1281         /*
1282          * Remove all other possibilities that were pointing at the
1283          * tile we've just moved into.
1284          */
1285         for (d = 1; d < 0x10; d <<= 1) {
1286             int x3, y3, d3;
1287             struct xyd xyd1, *xydp;
1288
1289             OFFSET(x3, y3, x2, y2, d, params);
1290             d3 = F(d);
1291
1292             xyd1.x = x3;
1293             xyd1.y = y3;
1294             xyd1.direction = d3;
1295
1296             xydp = find234(possibilities, &xyd1, NULL);
1297
1298             if (xydp) {
1299 #ifdef DEBUG
1300                 printf("Loop avoidance; removing (%d,%d,%c)\n",
1301                        xydp->x, xydp->y, "0RU3L567D9abcdef"[xydp->direction]);
1302 #endif
1303                 del234(possibilities, xydp);
1304                 sfree(xydp);
1305             }
1306         }
1307
1308         /*
1309          * Add new possibilities to the list for moving _out_ of
1310          * the tile we have just moved into.
1311          */
1312         for (d = 1; d < 0x10; d <<= 1) {
1313             int x3, y3;
1314
1315             if (d == d2)
1316                 continue;              /* we've got this one already */
1317
1318             if (!params->wrapping) {
1319                 if (d == U && y2 == 0)
1320                     continue;
1321                 if (d == D && y2 == h-1)
1322                     continue;
1323                 if (d == L && x2 == 0)
1324                     continue;
1325                 if (d == R && x2 == w-1)
1326                     continue;
1327             }
1328
1329             OFFSET(x3, y3, x2, y2, d, params);
1330
1331             if (index(params, tiles, x3, y3))
1332                 continue;              /* this would create a loop */
1333
1334 #ifdef DEBUG
1335             printf("New frontier; adding (%d,%d,%c)\n",
1336                    x2, y2, "0RU3L567D9abcdef"[d]);
1337 #endif
1338             add234(possibilities, new_xyd(x2, y2, d));
1339         }
1340     }
1341     /* Having done that, we should have no possibilities remaining. */
1342     assert(count234(possibilities) == 0);
1343     freetree234(possibilities);
1344
1345     if (params->unique) {
1346         int prevn = -1;
1347
1348         /*
1349          * Run the solver to check unique solubility.
1350          */
1351         while (!net_solver(w, h, tiles, NULL, params->wrapping)) {
1352             int n = 0;
1353
1354             /*
1355              * We expect (in most cases) that most of the grid will
1356              * be uniquely specified already, and the remaining
1357              * ambiguous sections will be small and separate. So
1358              * our strategy is to find each individual such
1359              * section, and perform a perturbation on the network
1360              * in that area.
1361              */
1362             for (y = 0; y < h; y++) for (x = 0; x < w; x++) {
1363                 if (x+1 < w && ((tiles[y*w+x] ^ tiles[y*w+x+1]) & LOCKED)) {
1364                     n++;
1365                     if (tiles[y*w+x] & LOCKED)
1366                         perturb(w, h, tiles, params->wrapping, rs, x+1, y, L);
1367                     else
1368                         perturb(w, h, tiles, params->wrapping, rs, x, y, R);
1369                 }
1370                 if (y+1 < h && ((tiles[y*w+x] ^ tiles[(y+1)*w+x]) & LOCKED)) {
1371                     n++;
1372                     if (tiles[y*w+x] & LOCKED)
1373                         perturb(w, h, tiles, params->wrapping, rs, x, y+1, U);
1374                     else
1375                         perturb(w, h, tiles, params->wrapping, rs, x, y, D);
1376                 }
1377             }
1378
1379             /*
1380              * Now n counts the number of ambiguous sections we
1381              * have fiddled with. If we haven't managed to decrease
1382              * it from the last time we ran the solver, give up and
1383              * regenerate the entire grid.
1384              */
1385             if (prevn != -1 && prevn <= n)
1386                 goto begin_generation; /* (sorry) */
1387
1388             prevn = n;
1389         }
1390
1391         /*
1392          * The solver will have left a lot of LOCKED bits lying
1393          * around in the tiles array. Remove them.
1394          */
1395         for (x = 0; x < w*h; x++)
1396             tiles[x] &= ~LOCKED;
1397     }
1398
1399     /*
1400      * Now compute a list of the possible barrier locations.
1401      */
1402     barriertree = newtree234(xyd_cmp_nc);
1403     for (y = 0; y < h; y++) {
1404         for (x = 0; x < w; x++) {
1405
1406             if (!(index(params, tiles, x, y) & R) &&
1407                 (params->wrapping || x < w-1))
1408                 add234(barriertree, new_xyd(x, y, R));
1409             if (!(index(params, tiles, x, y) & D) &&
1410                 (params->wrapping || y < h-1))
1411                 add234(barriertree, new_xyd(x, y, D));
1412         }
1413     }
1414
1415     /*
1416      * Save the unshuffled grid in an aux_info.
1417      */
1418     {
1419         game_aux_info *solution;
1420
1421         solution = snew(game_aux_info);
1422         solution->width = w;
1423         solution->height = h;
1424         solution->tiles = snewn(w * h, unsigned char);
1425         memcpy(solution->tiles, tiles, w * h);
1426
1427         *aux = solution;
1428     }
1429
1430     /*
1431      * Now shuffle the grid.
1432      */
1433     for (y = 0; y < h; y++) {
1434         for (x = 0; x < w; x++) {
1435             int orig = index(params, tiles, x, y);
1436             int rot = random_upto(rs, 4);
1437             index(params, tiles, x, y) = ROT(orig, rot);
1438         }
1439     }
1440
1441     /*
1442      * And now choose barrier locations. (We carefully do this
1443      * _after_ shuffling, so that changing the barrier rate in the
1444      * params while keeping the random seed the same will give the
1445      * same shuffled grid and _only_ change the barrier locations.
1446      * Also the way we choose barrier locations, by repeatedly
1447      * choosing one possibility from the list until we have enough,
1448      * is designed to ensure that raising the barrier rate while
1449      * keeping the seed the same will provide a superset of the
1450      * previous barrier set - i.e. if you ask for 10 barriers, and
1451      * then decide that's still too hard and ask for 20, you'll get
1452      * the original 10 plus 10 more, rather than getting 20 new
1453      * ones and the chance of remembering your first 10.)
1454      */
1455     nbarriers = (int)(params->barrier_probability * count234(barriertree));
1456     assert(nbarriers >= 0 && nbarriers <= count234(barriertree));
1457
1458     while (nbarriers > 0) {
1459         int i;
1460         struct xyd *xyd;
1461         int x1, y1, d1, x2, y2, d2;
1462
1463         /*
1464          * Extract a randomly chosen barrier from the list.
1465          */
1466         i = random_upto(rs, count234(barriertree));
1467         xyd = delpos234(barriertree, i);
1468
1469         assert(xyd != NULL);
1470
1471         x1 = xyd->x;
1472         y1 = xyd->y;
1473         d1 = xyd->direction;
1474         sfree(xyd);
1475
1476         OFFSET(x2, y2, x1, y1, d1, params);
1477         d2 = F(d1);
1478
1479         index(params, barriers, x1, y1) |= d1;
1480         index(params, barriers, x2, y2) |= d2;
1481
1482         nbarriers--;
1483     }
1484
1485     /*
1486      * Clean up the rest of the barrier list.
1487      */
1488     {
1489         struct xyd *xyd;
1490
1491         while ( (xyd = delpos234(barriertree, 0)) != NULL)
1492             sfree(xyd);
1493
1494         freetree234(barriertree);
1495     }
1496
1497     /*
1498      * Finally, encode the grid into a string game description.
1499      * 
1500      * My syntax is extremely simple: each square is encoded as a
1501      * hex digit in which bit 0 means a connection on the right,
1502      * bit 1 means up, bit 2 left and bit 3 down. (i.e. the same
1503      * encoding as used internally). Each digit is followed by
1504      * optional barrier indicators: `v' means a vertical barrier to
1505      * the right of it, and `h' means a horizontal barrier below
1506      * it.
1507      */
1508     desc = snewn(w * h * 3 + 1, char);
1509     p = desc;
1510     for (y = 0; y < h; y++) {
1511         for (x = 0; x < w; x++) {
1512             *p++ = "0123456789abcdef"[index(params, tiles, x, y)];
1513             if ((params->wrapping || x < w-1) &&
1514                 (index(params, barriers, x, y) & R))
1515                 *p++ = 'v';
1516             if ((params->wrapping || y < h-1) &&
1517                 (index(params, barriers, x, y) & D))
1518                 *p++ = 'h';
1519         }
1520     }
1521     assert(p - desc <= w*h*3);
1522     *p = '\0';
1523
1524     sfree(tiles);
1525     sfree(barriers);
1526
1527     return desc;
1528 }
1529
1530 static void game_free_aux_info(game_aux_info *aux)
1531 {
1532     sfree(aux->tiles);
1533     sfree(aux);
1534 }
1535
1536 static char *validate_desc(game_params *params, char *desc)
1537 {
1538     int w = params->width, h = params->height;
1539     int i;
1540
1541     for (i = 0; i < w*h; i++) {
1542         if (*desc >= '0' && *desc <= '9')
1543             /* OK */;
1544         else if (*desc >= 'a' && *desc <= 'f')
1545             /* OK */;
1546         else if (*desc >= 'A' && *desc <= 'F')
1547             /* OK */;
1548         else if (!*desc)
1549             return "Game description shorter than expected";
1550         else
1551             return "Game description contained unexpected character";
1552         desc++;
1553         while (*desc == 'h' || *desc == 'v')
1554             desc++;
1555     }
1556     if (*desc)
1557         return "Game description longer than expected";
1558
1559     return NULL;
1560 }
1561
1562 /* ----------------------------------------------------------------------
1563  * Construct an initial game state, given a description and parameters.
1564  */
1565
1566 static game_state *new_game(game_params *params, char *desc)
1567 {
1568     game_state *state;
1569     int w, h, x, y;
1570
1571     assert(params->width > 0 && params->height > 0);
1572     assert(params->width > 1 || params->height > 1);
1573
1574     /*
1575      * Create a blank game state.
1576      */
1577     state = snew(game_state);
1578     w = state->width = params->width;
1579     h = state->height = params->height;
1580     state->wrapping = params->wrapping;
1581     state->last_rotate_dir = state->last_rotate_x = state->last_rotate_y = 0;
1582     state->completed = state->used_solve = state->just_used_solve = FALSE;
1583     state->tiles = snewn(state->width * state->height, unsigned char);
1584     memset(state->tiles, 0, state->width * state->height);
1585     state->barriers = snewn(state->width * state->height, unsigned char);
1586     memset(state->barriers, 0, state->width * state->height);
1587
1588     /*
1589      * Parse the game description into the grid.
1590      */
1591     for (y = 0; y < h; y++) {
1592         for (x = 0; x < w; x++) {
1593             if (*desc >= '0' && *desc <= '9')
1594                 tile(state, x, y) = *desc - '0';
1595             else if (*desc >= 'a' && *desc <= 'f')
1596                 tile(state, x, y) = *desc - 'a' + 10;
1597             else if (*desc >= 'A' && *desc <= 'F')
1598                 tile(state, x, y) = *desc - 'A' + 10;
1599             if (*desc)
1600                 desc++;
1601             while (*desc == 'h' || *desc == 'v') {
1602                 int x2, y2, d1, d2;
1603                 if (*desc == 'v')
1604                     d1 = R;
1605                 else
1606                     d1 = D;
1607
1608                 OFFSET(x2, y2, x, y, d1, state);
1609                 d2 = F(d1);
1610
1611                 barrier(state, x, y) |= d1;
1612                 barrier(state, x2, y2) |= d2;
1613
1614                 desc++;
1615             }
1616         }
1617     }
1618
1619     /*
1620      * Set up border barriers if this is a non-wrapping game.
1621      */
1622     if (!state->wrapping) {
1623         for (x = 0; x < state->width; x++) {
1624             barrier(state, x, 0) |= U;
1625             barrier(state, x, state->height-1) |= D;
1626         }
1627         for (y = 0; y < state->height; y++) {
1628             barrier(state, 0, y) |= L;
1629             barrier(state, state->width-1, y) |= R;
1630         }
1631     } else {
1632         /*
1633          * We check whether this is de-facto a non-wrapping game
1634          * despite the parameters, in case we were passed the
1635          * description of a non-wrapping game. This is so that we
1636          * can change some aspects of the UI behaviour.
1637          */
1638         state->wrapping = FALSE;
1639         for (x = 0; x < state->width; x++)
1640             if (!(barrier(state, x, 0) & U) ||
1641                 !(barrier(state, x, state->height-1) & D))
1642                 state->wrapping = TRUE;
1643         for (y = 0; y < state->width; y++)
1644             if (!(barrier(state, 0, y) & L) ||
1645                 !(barrier(state, state->width-1, y) & R))
1646                 state->wrapping = TRUE;
1647     }
1648
1649     /*
1650      * Set up the barrier corner flags, for drawing barriers
1651      * prettily when they meet.
1652      */
1653     for (y = 0; y < state->height; y++) {
1654         for (x = 0; x < state->width; x++) {
1655             int dir;
1656
1657             for (dir = 1; dir < 0x10; dir <<= 1) {
1658                 int dir2 = A(dir);
1659                 int x1, y1, x2, y2, x3, y3;
1660                 int corner = FALSE;
1661
1662                 if (!(barrier(state, x, y) & dir))
1663                     continue;
1664
1665                 if (barrier(state, x, y) & dir2)
1666                     corner = TRUE;
1667
1668                 OFFSET(x1, y1, x, y, dir, state);
1669                 if (barrier(state, x1, y1) & dir2)
1670                     corner = TRUE;
1671
1672                 OFFSET(x2, y2, x, y, dir2, state);
1673                 if (barrier(state, x2, y2) & dir)
1674                     corner = TRUE;
1675
1676                 if (corner) {
1677                     barrier(state, x, y) |= (dir << 4);
1678                     barrier(state, x1, y1) |= (A(dir) << 4);
1679                     barrier(state, x2, y2) |= (C(dir) << 4);
1680                     OFFSET(x3, y3, x1, y1, dir2, state);
1681                     barrier(state, x3, y3) |= (F(dir) << 4);
1682                 }
1683             }
1684         }
1685     }
1686
1687     return state;
1688 }
1689
1690 static game_state *dup_game(game_state *state)
1691 {
1692     game_state *ret;
1693
1694     ret = snew(game_state);
1695     ret->width = state->width;
1696     ret->height = state->height;
1697     ret->wrapping = state->wrapping;
1698     ret->completed = state->completed;
1699     ret->used_solve = state->used_solve;
1700     ret->just_used_solve = state->just_used_solve;
1701     ret->last_rotate_dir = state->last_rotate_dir;
1702     ret->last_rotate_x = state->last_rotate_x;
1703     ret->last_rotate_y = state->last_rotate_y;
1704     ret->tiles = snewn(state->width * state->height, unsigned char);
1705     memcpy(ret->tiles, state->tiles, state->width * state->height);
1706     ret->barriers = snewn(state->width * state->height, unsigned char);
1707     memcpy(ret->barriers, state->barriers, state->width * state->height);
1708
1709     return ret;
1710 }
1711
1712 static void free_game(game_state *state)
1713 {
1714     sfree(state->tiles);
1715     sfree(state->barriers);
1716     sfree(state);
1717 }
1718
1719 static game_state *solve_game(game_state *state, game_aux_info *aux,
1720                               char **error)
1721 {
1722     game_state *ret;
1723
1724     if (!aux) {
1725         /*
1726          * Run the internal solver on the provided grid. This might
1727          * not yield a complete solution.
1728          */
1729         ret = dup_game(state);
1730         net_solver(ret->width, ret->height, ret->tiles,
1731                    ret->barriers, ret->wrapping);
1732     } else {
1733         assert(aux->width == state->width);
1734         assert(aux->height == state->height);
1735         ret = dup_game(state);
1736         memcpy(ret->tiles, aux->tiles, ret->width * ret->height);
1737         ret->used_solve = ret->just_used_solve = TRUE;
1738         ret->completed = TRUE;
1739     }
1740
1741     return ret;
1742 }
1743
1744 static char *game_text_format(game_state *state)
1745 {
1746     return NULL;
1747 }
1748
1749 /* ----------------------------------------------------------------------
1750  * Utility routine.
1751  */
1752
1753 /*
1754  * Compute which squares are reachable from the centre square, as a
1755  * quick visual aid to determining how close the game is to
1756  * completion. This is also a simple way to tell if the game _is_
1757  * completed - just call this function and see whether every square
1758  * is marked active.
1759  */
1760 static unsigned char *compute_active(game_state *state, int cx, int cy)
1761 {
1762     unsigned char *active;
1763     tree234 *todo;
1764     struct xyd *xyd;
1765
1766     active = snewn(state->width * state->height, unsigned char);
1767     memset(active, 0, state->width * state->height);
1768
1769     /*
1770      * We only store (x,y) pairs in todo, but it's easier to reuse
1771      * xyd_cmp and just store direction 0 every time.
1772      */
1773     todo = newtree234(xyd_cmp_nc);
1774     index(state, active, cx, cy) = ACTIVE;
1775     add234(todo, new_xyd(cx, cy, 0));
1776
1777     while ( (xyd = delpos234(todo, 0)) != NULL) {
1778         int x1, y1, d1, x2, y2, d2;
1779
1780         x1 = xyd->x;
1781         y1 = xyd->y;
1782         sfree(xyd);
1783
1784         for (d1 = 1; d1 < 0x10; d1 <<= 1) {
1785             OFFSET(x2, y2, x1, y1, d1, state);
1786             d2 = F(d1);
1787
1788             /*
1789              * If the next tile in this direction is connected to
1790              * us, and there isn't a barrier in the way, and it
1791              * isn't already marked active, then mark it active and
1792              * add it to the to-examine list.
1793              */
1794             if ((tile(state, x1, y1) & d1) &&
1795                 (tile(state, x2, y2) & d2) &&
1796                 !(barrier(state, x1, y1) & d1) &&
1797                 !index(state, active, x2, y2)) {
1798                 index(state, active, x2, y2) = ACTIVE;
1799                 add234(todo, new_xyd(x2, y2, 0));
1800             }
1801         }
1802     }
1803     /* Now we expect the todo list to have shrunk to zero size. */
1804     assert(count234(todo) == 0);
1805     freetree234(todo);
1806
1807     return active;
1808 }
1809
1810 struct game_ui {
1811     int org_x, org_y; /* origin */
1812     int cx, cy;       /* source tile (game coordinates) */
1813     int cur_x, cur_y;
1814     int cur_visible;
1815     random_state *rs; /* used for jumbling */
1816 };
1817
1818 static game_ui *new_ui(game_state *state)
1819 {
1820     void *seed;
1821     int seedsize;
1822     game_ui *ui = snew(game_ui);
1823     ui->org_x = ui->org_y = 0;
1824     ui->cur_x = ui->cx = state->width / 2;
1825     ui->cur_y = ui->cy = state->height / 2;
1826     ui->cur_visible = FALSE;
1827     get_random_seed(&seed, &seedsize);
1828     ui->rs = random_init(seed, seedsize);
1829     sfree(seed);
1830
1831     return ui;
1832 }
1833
1834 static void free_ui(game_ui *ui)
1835 {
1836     random_free(ui->rs);
1837     sfree(ui);
1838 }
1839
1840 /* ----------------------------------------------------------------------
1841  * Process a move.
1842  */
1843 static game_state *make_move(game_state *state, game_ui *ui,
1844                              int x, int y, int button)
1845 {
1846     game_state *ret, *nullret;
1847     int tx, ty, orig;
1848     int shift = button & MOD_SHFT, ctrl = button & MOD_CTRL;
1849
1850     button &= ~MOD_MASK;
1851     nullret = NULL;
1852
1853     if (button == LEFT_BUTTON ||
1854         button == MIDDLE_BUTTON ||
1855         button == RIGHT_BUTTON) {
1856
1857         if (ui->cur_visible) {
1858             ui->cur_visible = FALSE;
1859             nullret = state;
1860         }
1861
1862         /*
1863          * The button must have been clicked on a valid tile.
1864          */
1865         x -= WINDOW_OFFSET + TILE_BORDER;
1866         y -= WINDOW_OFFSET + TILE_BORDER;
1867         if (x < 0 || y < 0)
1868             return nullret;
1869         tx = x / TILE_SIZE;
1870         ty = y / TILE_SIZE;
1871         if (tx >= state->width || ty >= state->height)
1872             return nullret;
1873         /* Transform from physical to game coords */
1874         tx = (tx + ui->org_x) % state->width;
1875         ty = (ty + ui->org_y) % state->height;
1876         if (x % TILE_SIZE >= TILE_SIZE - TILE_BORDER ||
1877             y % TILE_SIZE >= TILE_SIZE - TILE_BORDER)
1878             return nullret;
1879     } else if (button == CURSOR_UP || button == CURSOR_DOWN ||
1880                button == CURSOR_RIGHT || button == CURSOR_LEFT) {
1881         int dir;
1882         switch (button) {
1883           case CURSOR_UP:       dir = U; break;
1884           case CURSOR_DOWN:     dir = D; break;
1885           case CURSOR_LEFT:     dir = L; break;
1886           case CURSOR_RIGHT:    dir = R; break;
1887           default:              return nullret;
1888         }
1889         if (shift) {
1890             /*
1891              * Move origin.
1892              */
1893             if (state->wrapping) {
1894                 OFFSET(ui->org_x, ui->org_y, ui->org_x, ui->org_y, dir, state);
1895             } else return nullret; /* disallowed for non-wrapping grids */
1896         }
1897         if (ctrl) {
1898             /*
1899              * Change source tile.
1900              */
1901             OFFSET(ui->cx, ui->cy, ui->cx, ui->cy, dir, state);
1902         }
1903         if (!shift && !ctrl) {
1904             /*
1905              * Move keyboard cursor.
1906              */
1907             OFFSET(ui->cur_x, ui->cur_y, ui->cur_x, ui->cur_y, dir, state);
1908             ui->cur_visible = TRUE;
1909         }
1910         return state;                  /* UI activity has occurred */
1911     } else if (button == 'a' || button == 's' || button == 'd' ||
1912                button == 'A' || button == 'S' || button == 'D') {
1913         tx = ui->cur_x;
1914         ty = ui->cur_y;
1915         if (button == 'a' || button == 'A')
1916             button = LEFT_BUTTON;
1917         else if (button == 's' || button == 'S')
1918             button = MIDDLE_BUTTON;
1919         else if (button == 'd' || button == 'D')
1920             button = RIGHT_BUTTON;
1921         ui->cur_visible = TRUE;
1922     } else if (button == 'j' || button == 'J') {
1923         /* XXX should we have some mouse control for this? */
1924         button = 'J';   /* canonify */
1925         tx = ty = -1;   /* shut gcc up :( */
1926     } else
1927         return nullret;
1928
1929     /*
1930      * The middle button locks or unlocks a tile. (A locked tile
1931      * cannot be turned, and is visually marked as being locked.
1932      * This is a convenience for the player, so that once they are
1933      * sure which way round a tile goes, they can lock it and thus
1934      * avoid forgetting later on that they'd already done that one;
1935      * and the locking also prevents them turning the tile by
1936      * accident. If they change their mind, another middle click
1937      * unlocks it.)
1938      */
1939     if (button == MIDDLE_BUTTON) {
1940
1941         ret = dup_game(state);
1942         ret->just_used_solve = FALSE;
1943         tile(ret, tx, ty) ^= LOCKED;
1944         ret->last_rotate_dir = ret->last_rotate_x = ret->last_rotate_y = 0;
1945         return ret;
1946
1947     } else if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
1948
1949         /*
1950          * The left and right buttons have no effect if clicked on a
1951          * locked tile.
1952          */
1953         if (tile(state, tx, ty) & LOCKED)
1954             return nullret;
1955
1956         /*
1957          * Otherwise, turn the tile one way or the other. Left button
1958          * turns anticlockwise; right button turns clockwise.
1959          */
1960         ret = dup_game(state);
1961         ret->just_used_solve = FALSE;
1962         orig = tile(ret, tx, ty);
1963         if (button == LEFT_BUTTON) {
1964             tile(ret, tx, ty) = A(orig);
1965             ret->last_rotate_dir = +1;
1966         } else {
1967             tile(ret, tx, ty) = C(orig);
1968             ret->last_rotate_dir = -1;
1969         }
1970         ret->last_rotate_x = tx;
1971         ret->last_rotate_y = ty;
1972
1973     } else if (button == 'J') {
1974
1975         /*
1976          * Jumble all unlocked tiles to random orientations.
1977          */
1978         int jx, jy;
1979         ret = dup_game(state);
1980         ret->just_used_solve = FALSE;
1981         for (jy = 0; jy < ret->height; jy++) {
1982             for (jx = 0; jx < ret->width; jx++) {
1983                 if (!(tile(ret, jx, jy) & LOCKED)) {
1984                     int rot = random_upto(ui->rs, 4);
1985                     orig = tile(ret, jx, jy);
1986                     tile(ret, jx, jy) = ROT(orig, rot);
1987                 }
1988             }
1989         }
1990         ret->last_rotate_dir = 0; /* suppress animation */
1991         ret->last_rotate_x = ret->last_rotate_y = 0;
1992
1993     } else assert(0);
1994
1995     /*
1996      * Check whether the game has been completed.
1997      */
1998     {
1999         unsigned char *active = compute_active(ret, ui->cx, ui->cy);
2000         int x1, y1;
2001         int complete = TRUE;
2002
2003         for (x1 = 0; x1 < ret->width; x1++)
2004             for (y1 = 0; y1 < ret->height; y1++)
2005                 if ((tile(ret, x1, y1) & 0xF) && !index(ret, active, x1, y1)) {
2006                     complete = FALSE;
2007                     goto break_label;  /* break out of two loops at once */
2008                 }
2009         break_label:
2010
2011         sfree(active);
2012
2013         if (complete)
2014             ret->completed = TRUE;
2015     }
2016
2017     return ret;
2018 }
2019
2020 /* ----------------------------------------------------------------------
2021  * Routines for drawing the game position on the screen.
2022  */
2023
2024 struct game_drawstate {
2025     int started;
2026     int width, height;
2027     int org_x, org_y;
2028     unsigned char *visible;
2029 };
2030
2031 static game_drawstate *game_new_drawstate(game_state *state)
2032 {
2033     game_drawstate *ds = snew(game_drawstate);
2034
2035     ds->started = FALSE;
2036     ds->width = state->width;
2037     ds->height = state->height;
2038     ds->org_x = ds->org_y = -1;
2039     ds->visible = snewn(state->width * state->height, unsigned char);
2040     memset(ds->visible, 0xFF, state->width * state->height);
2041
2042     return ds;
2043 }
2044
2045 static void game_free_drawstate(game_drawstate *ds)
2046 {
2047     sfree(ds->visible);
2048     sfree(ds);
2049 }
2050
2051 static void game_size(game_params *params, int *x, int *y)
2052 {
2053     *x = WINDOW_OFFSET * 2 + TILE_SIZE * params->width + TILE_BORDER;
2054     *y = WINDOW_OFFSET * 2 + TILE_SIZE * params->height + TILE_BORDER;
2055 }
2056
2057 static float *game_colours(frontend *fe, game_state *state, int *ncolours)
2058 {
2059     float *ret;
2060
2061     ret = snewn(NCOLOURS * 3, float);
2062     *ncolours = NCOLOURS;
2063
2064     /*
2065      * Basic background colour is whatever the front end thinks is
2066      * a sensible default.
2067      */
2068     frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
2069
2070     /*
2071      * Wires are black.
2072      */
2073     ret[COL_WIRE * 3 + 0] = 0.0F;
2074     ret[COL_WIRE * 3 + 1] = 0.0F;
2075     ret[COL_WIRE * 3 + 2] = 0.0F;
2076
2077     /*
2078      * Powered wires and powered endpoints are cyan.
2079      */
2080     ret[COL_POWERED * 3 + 0] = 0.0F;
2081     ret[COL_POWERED * 3 + 1] = 1.0F;
2082     ret[COL_POWERED * 3 + 2] = 1.0F;
2083
2084     /*
2085      * Barriers are red.
2086      */
2087     ret[COL_BARRIER * 3 + 0] = 1.0F;
2088     ret[COL_BARRIER * 3 + 1] = 0.0F;
2089     ret[COL_BARRIER * 3 + 2] = 0.0F;
2090
2091     /*
2092      * Unpowered endpoints are blue.
2093      */
2094     ret[COL_ENDPOINT * 3 + 0] = 0.0F;
2095     ret[COL_ENDPOINT * 3 + 1] = 0.0F;
2096     ret[COL_ENDPOINT * 3 + 2] = 1.0F;
2097
2098     /*
2099      * Tile borders are a darker grey than the background.
2100      */
2101     ret[COL_BORDER * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0];
2102     ret[COL_BORDER * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1];
2103     ret[COL_BORDER * 3 + 2] = 0.5F * ret[COL_BACKGROUND * 3 + 2];
2104
2105     /*
2106      * Locked tiles are a grey in between those two.
2107      */
2108     ret[COL_LOCKED * 3 + 0] = 0.75F * ret[COL_BACKGROUND * 3 + 0];
2109     ret[COL_LOCKED * 3 + 1] = 0.75F * ret[COL_BACKGROUND * 3 + 1];
2110     ret[COL_LOCKED * 3 + 2] = 0.75F * ret[COL_BACKGROUND * 3 + 2];
2111
2112     return ret;
2113 }
2114
2115 static void draw_thick_line(frontend *fe, int x1, int y1, int x2, int y2,
2116                             int colour)
2117 {
2118     draw_line(fe, x1-1, y1, x2-1, y2, COL_WIRE);
2119     draw_line(fe, x1+1, y1, x2+1, y2, COL_WIRE);
2120     draw_line(fe, x1, y1-1, x2, y2-1, COL_WIRE);
2121     draw_line(fe, x1, y1+1, x2, y2+1, COL_WIRE);
2122     draw_line(fe, x1, y1, x2, y2, colour);
2123 }
2124
2125 static void draw_rect_coords(frontend *fe, int x1, int y1, int x2, int y2,
2126                              int colour)
2127 {
2128     int mx = (x1 < x2 ? x1 : x2);
2129     int my = (y1 < y2 ? y1 : y2);
2130     int dx = (x2 + x1 - 2*mx + 1);
2131     int dy = (y2 + y1 - 2*my + 1);
2132
2133     draw_rect(fe, mx, my, dx, dy, colour);
2134 }
2135
2136 /*
2137  * draw_barrier_corner() and draw_barrier() are passed physical coords
2138  */
2139 static void draw_barrier_corner(frontend *fe, int x, int y, int dir, int phase,
2140                                 int barrier)
2141 {
2142     int bx = WINDOW_OFFSET + TILE_SIZE * x;
2143     int by = WINDOW_OFFSET + TILE_SIZE * y;
2144     int x1, y1, dx, dy, dir2;
2145
2146     dir >>= 4;
2147
2148     dir2 = A(dir);
2149     dx = X(dir) + X(dir2);
2150     dy = Y(dir) + Y(dir2);
2151     x1 = (dx > 0 ? TILE_SIZE+TILE_BORDER-1 : 0);
2152     y1 = (dy > 0 ? TILE_SIZE+TILE_BORDER-1 : 0);
2153
2154     if (phase == 0) {
2155         draw_rect_coords(fe, bx+x1, by+y1,
2156                          bx+x1-TILE_BORDER*dx, by+y1-(TILE_BORDER-1)*dy,
2157                          barrier ? COL_WIRE : COL_BACKGROUND);
2158         draw_rect_coords(fe, bx+x1, by+y1,
2159                          bx+x1-(TILE_BORDER-1)*dx, by+y1-TILE_BORDER*dy,
2160                          barrier ? COL_WIRE : COL_BACKGROUND);
2161     } else {
2162         draw_rect_coords(fe, bx+x1, by+y1,
2163                          bx+x1-(TILE_BORDER-1)*dx, by+y1-(TILE_BORDER-1)*dy,
2164                          barrier ? COL_BARRIER : COL_BORDER);
2165     }
2166 }
2167
2168 static void draw_barrier(frontend *fe, int x, int y, int dir, int phase,
2169                          int barrier)
2170 {
2171     int bx = WINDOW_OFFSET + TILE_SIZE * x;
2172     int by = WINDOW_OFFSET + TILE_SIZE * y;
2173     int x1, y1, w, h;
2174
2175     x1 = (X(dir) > 0 ? TILE_SIZE : X(dir) == 0 ? TILE_BORDER : 0);
2176     y1 = (Y(dir) > 0 ? TILE_SIZE : Y(dir) == 0 ? TILE_BORDER : 0);
2177     w = (X(dir) ? TILE_BORDER : TILE_SIZE - TILE_BORDER);
2178     h = (Y(dir) ? TILE_BORDER : TILE_SIZE - TILE_BORDER);
2179
2180     if (phase == 0) {
2181         draw_rect(fe, bx+x1-X(dir), by+y1-Y(dir), w, h,
2182                   barrier ? COL_WIRE : COL_BACKGROUND);
2183     } else {
2184         draw_rect(fe, bx+x1, by+y1, w, h,
2185                   barrier ? COL_BARRIER : COL_BORDER);
2186     }
2187 }
2188
2189 /*
2190  * draw_tile() is passed physical coordinates
2191  */
2192 static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds,
2193                       int x, int y, int tile, int src, float angle, int cursor)
2194 {
2195     int bx = WINDOW_OFFSET + TILE_SIZE * x;
2196     int by = WINDOW_OFFSET + TILE_SIZE * y;
2197     float matrix[4];
2198     float cx, cy, ex, ey, tx, ty;
2199     int dir, col, phase;
2200
2201     /*
2202      * When we draw a single tile, we must draw everything up to
2203      * and including the borders around the tile. This means that
2204      * if the neighbouring tiles have connections to those borders,
2205      * we must draw those connections on the borders themselves.
2206      *
2207      * This would be terribly fiddly if we ever had to draw a tile
2208      * while its neighbour was in mid-rotate, because we'd have to
2209      * arrange to _know_ that the neighbour was being rotated and
2210      * hence had an anomalous effect on the redraw of this tile.
2211      * Fortunately, the drawing algorithm avoids ever calling us in
2212      * this circumstance: we're either drawing lots of straight
2213      * tiles at game start or after a move is complete, or we're
2214      * repeatedly drawing only the rotating tile. So no problem.
2215      */
2216
2217     /*
2218      * So. First blank the tile out completely: draw a big
2219      * rectangle in border colour, and a smaller rectangle in
2220      * background colour to fill it in.
2221      */
2222     draw_rect(fe, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER,
2223               COL_BORDER);
2224     draw_rect(fe, bx+TILE_BORDER, by+TILE_BORDER,
2225               TILE_SIZE-TILE_BORDER, TILE_SIZE-TILE_BORDER,
2226               tile & LOCKED ? COL_LOCKED : COL_BACKGROUND);
2227
2228     /*
2229      * Draw an inset outline rectangle as a cursor, in whichever of
2230      * COL_LOCKED and COL_BACKGROUND we aren't currently drawing
2231      * in.
2232      */
2233     if (cursor) {
2234         draw_line(fe, bx+TILE_SIZE/8, by+TILE_SIZE/8,
2235                   bx+TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8,
2236                   tile & LOCKED ? COL_BACKGROUND : COL_LOCKED);
2237         draw_line(fe, bx+TILE_SIZE/8, by+TILE_SIZE/8,
2238                   bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE/8,
2239                   tile & LOCKED ? COL_BACKGROUND : COL_LOCKED);
2240         draw_line(fe, bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE/8,
2241                   bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8,
2242                   tile & LOCKED ? COL_BACKGROUND : COL_LOCKED);
2243         draw_line(fe, bx+TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8,
2244                   bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8,
2245                   tile & LOCKED ? COL_BACKGROUND : COL_LOCKED);
2246     }
2247
2248     /*
2249      * Set up the rotation matrix.
2250      */
2251     matrix[0] = (float)cos(angle * PI / 180.0);
2252     matrix[1] = (float)-sin(angle * PI / 180.0);
2253     matrix[2] = (float)sin(angle * PI / 180.0);
2254     matrix[3] = (float)cos(angle * PI / 180.0);
2255
2256     /*
2257      * Draw the wires.
2258      */
2259     cx = cy = TILE_BORDER + (TILE_SIZE-TILE_BORDER) / 2.0F - 0.5F;
2260     col = (tile & ACTIVE ? COL_POWERED : COL_WIRE);
2261     for (dir = 1; dir < 0x10; dir <<= 1) {
2262         if (tile & dir) {
2263             ex = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * X(dir);
2264             ey = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * Y(dir);
2265             MATMUL(tx, ty, matrix, ex, ey);
2266             draw_thick_line(fe, bx+(int)cx, by+(int)cy,
2267                             bx+(int)(cx+tx), by+(int)(cy+ty),
2268                             COL_WIRE);
2269         }
2270     }
2271     for (dir = 1; dir < 0x10; dir <<= 1) {
2272         if (tile & dir) {
2273             ex = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * X(dir);
2274             ey = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * Y(dir);
2275             MATMUL(tx, ty, matrix, ex, ey);
2276             draw_line(fe, bx+(int)cx, by+(int)cy,
2277                       bx+(int)(cx+tx), by+(int)(cy+ty), col);
2278         }
2279     }
2280
2281     /*
2282      * Draw the box in the middle. We do this in blue if the tile
2283      * is an unpowered endpoint, in cyan if the tile is a powered
2284      * endpoint, in black if the tile is the centrepiece, and
2285      * otherwise not at all.
2286      */
2287     col = -1;
2288     if (src)
2289         col = COL_WIRE;
2290     else if (COUNT(tile) == 1) {
2291         col = (tile & ACTIVE ? COL_POWERED : COL_ENDPOINT);
2292     }
2293     if (col >= 0) {
2294         int i, points[8];
2295
2296         points[0] = +1; points[1] = +1;
2297         points[2] = +1; points[3] = -1;
2298         points[4] = -1; points[5] = -1;
2299         points[6] = -1; points[7] = +1;
2300
2301         for (i = 0; i < 8; i += 2) {
2302             ex = (TILE_SIZE * 0.24F) * points[i];
2303             ey = (TILE_SIZE * 0.24F) * points[i+1];
2304             MATMUL(tx, ty, matrix, ex, ey);
2305             points[i] = bx+(int)(cx+tx);
2306             points[i+1] = by+(int)(cy+ty);
2307         }
2308
2309         draw_polygon(fe, points, 4, TRUE, col);
2310         draw_polygon(fe, points, 4, FALSE, COL_WIRE);
2311     }
2312
2313     /*
2314      * Draw the points on the border if other tiles are connected
2315      * to us.
2316      */
2317     for (dir = 1; dir < 0x10; dir <<= 1) {
2318         int dx, dy, px, py, lx, ly, vx, vy, ox, oy;
2319
2320         dx = X(dir);
2321         dy = Y(dir);
2322
2323         ox = x + dx;
2324         oy = y + dy;
2325
2326         if (ox < 0 || ox >= state->width || oy < 0 || oy >= state->height)
2327             continue;
2328
2329         if (!(tile(state, GX(ox), GY(oy)) & F(dir)))
2330             continue;
2331
2332         px = bx + (int)(dx>0 ? TILE_SIZE + TILE_BORDER - 1 : dx<0 ? 0 : cx);
2333         py = by + (int)(dy>0 ? TILE_SIZE + TILE_BORDER - 1 : dy<0 ? 0 : cy);
2334         lx = dx * (TILE_BORDER-1);
2335         ly = dy * (TILE_BORDER-1);
2336         vx = (dy ? 1 : 0);
2337         vy = (dx ? 1 : 0);
2338
2339         if (angle == 0.0 && (tile & dir)) {
2340             /*
2341              * If we are fully connected to the other tile, we must
2342              * draw right across the tile border. (We can use our
2343              * own ACTIVE state to determine what colour to do this
2344              * in: if we are fully connected to the other tile then
2345              * the two ACTIVE states will be the same.)
2346              */
2347             draw_rect_coords(fe, px-vx, py-vy, px+lx+vx, py+ly+vy, COL_WIRE);
2348             draw_rect_coords(fe, px, py, px+lx, py+ly,
2349                              (tile & ACTIVE) ? COL_POWERED : COL_WIRE);
2350         } else {
2351             /*
2352              * The other tile extends into our border, but isn't
2353              * actually connected to us. Just draw a single black
2354              * dot.
2355              */
2356             draw_rect_coords(fe, px, py, px, py, COL_WIRE);
2357         }
2358     }
2359
2360     /*
2361      * Draw barrier corners, and then barriers.
2362      */
2363     for (phase = 0; phase < 2; phase++) {
2364         for (dir = 1; dir < 0x10; dir <<= 1)
2365             if (barrier(state, GX(x), GY(y)) & (dir << 4))
2366                 draw_barrier_corner(fe, x, y, dir << 4, phase, TRUE);
2367         for (dir = 1; dir < 0x10; dir <<= 1)
2368             if (barrier(state, GX(x), GY(y)) & dir)
2369                 draw_barrier(fe, x, y, dir, phase, TRUE);
2370     }
2371
2372     draw_update(fe, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER);
2373 }
2374
2375 static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
2376                  game_state *state, int dir, game_ui *ui, float t, float ft)
2377 {
2378     int x, y, tx, ty, frame, last_rotate_dir, moved_origin = FALSE;
2379     unsigned char *active;
2380     float angle = 0.0;
2381
2382     /*
2383      * Clear the screen if this is our first call.
2384      */
2385     if (!ds->started) {
2386         ds->started = TRUE;
2387
2388         draw_rect(fe, 0, 0, 
2389                   WINDOW_OFFSET * 2 + TILE_SIZE * state->width + TILE_BORDER,
2390                   WINDOW_OFFSET * 2 + TILE_SIZE * state->height + TILE_BORDER,
2391                   COL_BACKGROUND);
2392
2393     }
2394
2395     /*
2396      * If the origin has changed, we need to redraw the exterior
2397      * barrier lines.
2398      */
2399     if (ui->org_x != ds->org_x || ui->org_y != ds->org_y) {
2400         int phase;
2401
2402         ds->org_x = ui->org_x;
2403         ds->org_y = ui->org_y;
2404         moved_origin = TRUE;
2405
2406         draw_update(fe, 0, 0, 
2407                     WINDOW_OFFSET*2 + TILE_SIZE*state->width + TILE_BORDER,
2408                     WINDOW_OFFSET*2 + TILE_SIZE*state->height + TILE_BORDER);
2409         
2410         for (phase = 0; phase < 2; phase++) {
2411
2412             for (x = 0; x < ds->width; x++) {
2413                 int ub = barrier(state, GX(x), GY(0));
2414                 int db = barrier(state, GX(x), GY(ds->height-1));
2415                 draw_barrier_corner(fe, x, -1, LD, phase, ub & UL);
2416                 draw_barrier_corner(fe, x, -1, DR, phase, ub & RU);
2417                 draw_barrier(fe, x, -1, D, phase, ub & U);
2418                 draw_barrier_corner(fe, x, ds->height, RU, phase, db & DR);
2419                 draw_barrier_corner(fe, x, ds->height, UL, phase, db & LD);
2420                 draw_barrier(fe, x, ds->height, U, phase, db & D);
2421             }
2422
2423             for (y = 0; y < ds->height; y++) {
2424                 int lb = barrier(state, GX(0), GY(y));
2425                 int rb = barrier(state, GX(ds->width-1), GY(y));
2426                 draw_barrier_corner(fe, -1, y, RU, phase, lb & UL);
2427                 draw_barrier_corner(fe, -1, y, DR, phase, lb & LD);
2428                 draw_barrier(fe, -1, y, R, phase, lb & L);
2429                 draw_barrier_corner(fe, ds->width, y, UL, phase, rb & RU);
2430                 draw_barrier_corner(fe, ds->width, y, LD, phase, rb & DR);
2431                 draw_barrier(fe, ds->width, y, L, phase, rb & R);
2432             }
2433         }
2434     }
2435
2436     tx = ty = -1;
2437     last_rotate_dir = dir==-1 ? oldstate->last_rotate_dir :
2438                                 state->last_rotate_dir;
2439     if (oldstate && (t < ROTATE_TIME) && last_rotate_dir) {
2440         /*
2441          * We're animating a single tile rotation. Find the turning
2442          * tile.
2443          */
2444         tx = (dir==-1 ? oldstate->last_rotate_x : state->last_rotate_x);
2445         ty = (dir==-1 ? oldstate->last_rotate_y : state->last_rotate_y);
2446         angle = last_rotate_dir * dir * 90.0F * (t / ROTATE_TIME);
2447         state = oldstate;
2448     }
2449
2450     frame = -1;
2451     if (ft > 0) {
2452         /*
2453          * We're animating a completion flash. Find which frame
2454          * we're at.
2455          */
2456         frame = (int)(ft / FLASH_FRAME);
2457     }
2458
2459     /*
2460      * Draw any tile which differs from the way it was last drawn.
2461      */
2462     active = compute_active(state, ui->cx, ui->cy);
2463
2464     for (x = 0; x < ds->width; x++)
2465         for (y = 0; y < ds->height; y++) {
2466             unsigned char c = tile(state, GX(x), GY(y)) |
2467                               index(state, active, GX(x), GY(y));
2468             int is_src = GX(x) == ui->cx && GY(y) == ui->cy;
2469             int is_anim = GX(x) == tx && GY(y) == ty;
2470             int is_cursor = ui->cur_visible &&
2471                             GX(x) == ui->cur_x && GY(y) == ui->cur_y;
2472
2473             /*
2474              * In a completion flash, we adjust the LOCKED bit
2475              * depending on our distance from the centre point and
2476              * the frame number.
2477              */
2478             if (frame >= 0) {
2479                 int rcx = RX(ui->cx), rcy = RY(ui->cy);
2480                 int xdist, ydist, dist;
2481                 xdist = (x < rcx ? rcx - x : x - rcx);
2482                 ydist = (y < rcy ? rcy - y : y - rcy);
2483                 dist = (xdist > ydist ? xdist : ydist);
2484
2485                 if (frame >= dist && frame < dist+4) {
2486                     int lock = (frame - dist) & 1;
2487                     lock = lock ? LOCKED : 0;
2488                     c = (c &~ LOCKED) | lock;
2489                 }
2490             }
2491
2492             if (moved_origin ||
2493                 index(state, ds->visible, x, y) != c ||
2494                 index(state, ds->visible, x, y) == 0xFF ||
2495                 is_src || is_anim || is_cursor) {
2496                 draw_tile(fe, state, ds, x, y, c,
2497                           is_src, (is_anim ? angle : 0.0F), is_cursor);
2498                 if (is_src || is_anim || is_cursor)
2499                     index(state, ds->visible, x, y) = 0xFF;
2500                 else
2501                     index(state, ds->visible, x, y) = c;
2502             }
2503         }
2504
2505     /*
2506      * Update the status bar.
2507      */
2508     {
2509         char statusbuf[256];
2510         int i, n, n2, a;
2511
2512         n = state->width * state->height;
2513         for (i = a = n2 = 0; i < n; i++) {
2514             if (active[i])
2515                 a++;
2516             if (state->tiles[i] & 0xF)
2517                 n2++;
2518         }
2519
2520         sprintf(statusbuf, "%sActive: %d/%d",
2521                 (state->used_solve ? "Auto-solved. " :
2522                  state->completed ? "COMPLETED! " : ""), a, n2);
2523
2524         status_bar(fe, statusbuf);
2525     }
2526
2527     sfree(active);
2528 }
2529
2530 static float game_anim_length(game_state *oldstate,
2531                               game_state *newstate, int dir)
2532 {
2533     int last_rotate_dir;
2534
2535     /*
2536      * Don't animate an auto-solve move.
2537      */
2538     if ((dir > 0 && newstate->just_used_solve) ||
2539        (dir < 0 && oldstate->just_used_solve))
2540        return 0.0F;
2541
2542     /*
2543      * Don't animate if last_rotate_dir is zero.
2544      */
2545     last_rotate_dir = dir==-1 ? oldstate->last_rotate_dir :
2546                                 newstate->last_rotate_dir;
2547     if (last_rotate_dir)
2548         return ROTATE_TIME;
2549
2550     return 0.0F;
2551 }
2552
2553 static float game_flash_length(game_state *oldstate,
2554                                game_state *newstate, int dir)
2555 {
2556     /*
2557      * If the game has just been completed, we display a completion
2558      * flash.
2559      */
2560     if (!oldstate->completed && newstate->completed &&
2561         !oldstate->used_solve && !newstate->used_solve) {
2562         int size = 0;
2563         if (size < newstate->width)
2564             size = newstate->width;
2565         if (size < newstate->height)
2566             size = newstate->height;
2567         return FLASH_FRAME * (size+4);
2568     }
2569
2570     return 0.0F;
2571 }
2572
2573 static int game_wants_statusbar(void)
2574 {
2575     return TRUE;
2576 }
2577
2578 #ifdef COMBINED
2579 #define thegame net
2580 #endif
2581
2582 const struct game thegame = {
2583     "Net", "games.net",
2584     default_params,
2585     game_fetch_preset,
2586     decode_params,
2587     encode_params,
2588     free_params,
2589     dup_params,
2590     TRUE, game_configure, custom_params,
2591     validate_params,
2592     new_game_desc,
2593     game_free_aux_info,
2594     validate_desc,
2595     new_game,
2596     dup_game,
2597     free_game,
2598     TRUE, solve_game,
2599     FALSE, game_text_format,
2600     new_ui,
2601     free_ui,
2602     make_move,
2603     game_size,
2604     game_colours,
2605     game_new_drawstate,
2606     game_free_drawstate,
2607     game_redraw,
2608     game_anim_length,
2609     game_flash_length,
2610     game_wants_statusbar,
2611 };