source: trunk/third/xscreensaver/hacks/polyominoes.c @ 20148

Revision 20148, 60.9 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 4 -*- */
2/* polyominoes --- Shows attempts to place polyominoes into a rectangle */
3
4#if 0
5static const char sccsid[] = "@(#)polyominoes.c 5.01 2000/12/18 xlockmore";
6#endif
7
8/*
9 * Copyright (c) 2000 by Stephen Montgomery-Smith <stephen@math.missouri.edu>
10 *
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
16 *
17 * This file is provided AS IS with no warranties of any kind.  The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof.  In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
22 *
23 * Revision History:
24 * 07-Jan-2001: Made improvement to the search algorithm for the puzzles
25 *              involving identical polyominoes (via the variable
26 *              reason_to_not_attach).  By Stephen Montgomery-Smith.
27 * 20-Dec-2000: Added more puzzles at David Bagley's request.
28 * 27-Nov-2000: Adapted from euler2d.c Copyright (c) 2000 by Stephen
29 *              Montgomery-Smith
30 * 05-Jun-2000: Adapted from flow.c Copyright (c) 1996 by Tim Auckland
31 * 18-Jul-1996: Adapted from swarm.c Copyright (c) 1991 by Patrick J. Naughton.
32 * 31-Aug-1990: Adapted from xswarm by Jeff Butterworth. (butterwo@ncsc.org)
33 */
34
35#ifdef STANDALONE
36#define MODE_polyominoes
37#define PROGCLASS "Polyominoes"
38#define HACK_INIT init_polyominoes
39#define HACK_DRAW draw_polyominoes
40#define polyominoes_opts xlockmore_opts
41#define DEFAULTS "*delay: 10000 \n" \
42"*cycles: 2000 \n" \
43"*ncolors: 64 \n"
44#define SMOOTH_COLORS
45#include "xlockmore.h"          /* in xscreensaver distribution */
46#include "erase.h"
47#include <X11/Xutil.h>
48#else /* STANDALONE */
49#include "xlock.h"              /* in xlockmore distribution */
50#endif /* STANDALONE */
51
52#ifdef MODE_polyominoes
53#define DEF_IDENTICAL "False"
54#define DEF_PLAIN "False"
55
56static Bool identical;
57static Bool plain;
58
59static XrmOptionDescRec opts[] =
60{
61  {(char *) "-identical", (char *) ".polyominoes.identical", XrmoptionNoArg, (caddr_t) "on"},
62  {(char *) "+identical", (char *) ".polyominoes.identical", XrmoptionNoArg, (caddr_t) "off"},
63  {(char *) "-plain", (char *) ".polyominoes.plain", XrmoptionNoArg, (caddr_t) "on"},
64  {(char *) "+plain", (char *) ".polyominoes.plain", XrmoptionNoArg, (caddr_t) "off"}
65};
66static argtype vars[] =
67{
68  {(caddr_t *) &identical, (char *) "identical", (char *) "Identical", (char *) DEF_IDENTICAL, t_Bool},
69  {(caddr_t *) & plain, (char *) "plain", (char *) "Plain", (char *) DEF_PLAIN, t_Bool}
70};
71static OptionStruct desc[] =
72{
73  {(char *) "-/+identical", (char *) "turn on/off puzzles where the polyomino pieces are identical"},
74  {(char *) "-/+plain", (char *) "turn on/off plain pieces"}
75};
76
77ModeSpecOpt polyominoes_opts =
78{sizeof opts / sizeof opts[0], opts,
79 sizeof vars / sizeof vars[0], vars, desc};
80
81#ifdef USE_MODULES
82ModStruct   polyominoes_description = {
83  "polyominoes", "init_polyominoes", "draw_polyominoes", "release_polyominoes",
84  "refresh_polyominoes", "init_polyominoes", (char *) NULL, &polyominoes_opts,
85  6000, 1, 8192, 1, 64, 1.0, "",
86  "Shows attempts to place polyominoes into a rectangle", 0, NULL
87};
88
89#endif
90
91/* Each polyomino is described by several quantities:
92   len:             the number of squares in the polyomino;
93   point:           the list of points;
94   tranform_len:    the number of items in transform_list;
95   transform_list:  a list of transformations that need to be done in order
96                    to get all rotations and reflections (see the function
97                    transform below);
98   max_white:       the maximum number of white squares covered if polyomino
99                    is placed on a chess board;
100   color:           it's display color;
101   attached:        whether it is currently attached to the rectangle;
102   attach_point:    point on rectangle where attached;
103   point_no:        the number of the point where it is attached;
104   transform_index: which element of transform_list is currently being used.
105*/
106
107typedef struct {int x,y;} point_type;
108
109typedef struct {int len; point_type *point;
110                int transform_len, transform_list[8], max_white;
111                unsigned long color;
112                int attached;
113                point_type attach_point;
114                int point_no, transform_index;} polyomino_type;
115
116
117typedef struct _polyominoesstruct{
118  int wait;
119
120  int width, height;
121  unsigned border_color;
122  int mono;
123
124  polyomino_type *polyomino;
125  int nr_polyominoes;
126  Bool identical, use3D;
127  int *attach_list;
128  int nr_attached;
129
130/* The array that tells where the polyominoes are attached. */
131  int *array, *changed_array;
132
133/* These specify the dimensions of how things appear on the screen. */
134  int box, x_margin, y_margin;
135
136/* These booleans decide in which way to try to attach the polyominoes. */
137  int left_right, top_bottom;
138
139/* Bitmaps for display purposes. */
140  int use_bitmaps;
141  XImage *bitmaps[256];
142
143/* Structures used for display purposes if there is not enough memory
144   to allocate bitmaps (or if the screen is small). */
145  XSegment *lines;
146  XRectangle *rectangles;
147
148/* A procedure that may be used to see if certain configurations
149   are permissible. */
150  int (*check_ok)(struct _polyominoesstruct *sp);
151
152/* Tells program that solutions are invariant under 180 degree
153   rotation. */
154  int rot180;
155
156/* This is a variable used in the case that all the polyominoes are identical
157   that will further prune the search tree.  Essentially it will be
158   int reason_to_not_attach[nr_polynominoes][nr_polynominoes];
159   Let me first explain the effect it is trying to overcome.  Often
160   in the search process, the computer will first try to fit shapes into
161   a region (call it A), and then into another region (call it B) that is
162   essentially disjoint from A.  But it may be that it just is not possible
163   to fit shapes into region B.  So it fits something into A, and then
164   tries to fit something into B.  Failing it fits something else into A,
165   and then tried again to fit something into B.  Thus the program is trying
166   again and again to fit something into B, when it should have figured out
167   the first time that it was impossible.
168
169   To overcome this, everytime we try to attach a piece, we collect the reasons
170   why it cannot be attached (a boolean for each piece that got in the way).
171   If we see that a piece cannot be attached, we detach the other pieces until
172   we have detached at least one piece for which the boolean reason_to_not_attach
173   is set.
174*/
175  int *reason_to_not_attach;
176
177  int counter;
178} polyominoesstruct;
179
180#define ARRAY(x,y)         (sp->array[(x)*sp->height+(y)])
181#define CHANGED_ARRAY(x,y) (sp->changed_array[(x)*sp->height+(y)])
182#define ARRAY_P(p)         (sp->array[(p).x*sp->height+(p).y])
183#define CHANGED_ARRAY_P(p) (sp->changed_array[(p).x*sp->height+(p).y])
184#define ARR(x,y) (((x)<0||(x)>=sp->width||(y)<0||(y)>=sp->height)?-2:ARRAY(x,y))
185
186#define REASON_TO_NOT_ATTACH(x,y) (sp->reason_to_not_attach[(x)*sp->nr_polyominoes+(y)])
187
188#define ROUND8(n) ((((n)+7)/8)*8)
189
190/* Defines to index the bitmaps.  A set bit indicates that an edge or
191   corner is required. */
192#define LEFT (1<<0)
193#define RIGHT (1<<1)
194#define UP (1<<2)
195#define DOWN (1<<3)
196#define LEFT_UP (1<<4)
197#define LEFT_DOWN (1<<5)
198#define RIGHT_UP (1<<6)
199#define RIGHT_DOWN (1<<7)
200#define IS_LEFT(n) ((n) & LEFT)
201#define IS_RIGHT(n) ((n) & RIGHT)
202#define IS_UP(n) ((n) & UP)
203#define IS_DOWN(n) ((n) & DOWN)
204#define IS_LEFT_UP(n) ((n) & LEFT_UP)
205#define IS_LEFT_DOWN(n) ((n) & LEFT_DOWN)
206#define IS_RIGHT_UP(n) ((n) & RIGHT_UP)
207#define IS_RIGHT_DOWN(n) ((n) & RIGHT_DOWN)
208
209/* Defines to access the bitmaps. */
210#define BITNO(x,y) ((x)+(y)*ROUND8(sp->box))
211#define SETBIT(n,x,y) {data[BITNO(x,y)/8] |= 1<<(BITNO(x,y)%8);}
212#define RESBIT(n,x,y) {data[BITNO(x,y)/8] &= ~(1<<(BITNO(x,y)%8));}
213#define TWOTHIRDSBIT(n,x,y) {if ((x+y-1)%3) SETBIT(n,x,y) else RESBIT(n,x,y)}
214#define HALFBIT(n,x,y) {if ((x-y)%2) SETBIT(n,x,y) else RESBIT(n,x,y)}
215#define THIRDBIT(n,x,y) {if (!((x-y-1)%3)) SETBIT(n,x,y) else RESBIT(n,x,y)}
216#define THREEQUARTERSBIT(n,x,y) \
217  {if ((y%2)||((x+2+y/2+1)%2)) SETBIT(n,x,y) else RESBIT(n,x,y)}
218#define NOTHALFBIT(n,x,y) {if ((x-y)%2) RESBIT(n,x,y) else SETBIT(n,x,y)}
219
220/* Parameters for bitmaps. */
221#define G ((sp->box/45)+1)         /* 1/2 of gap between polyominoes. */
222#define T ((sp->box<=12)?1:(G*2))  /* Thickness of walls of polyominoes. */
223#define R ((sp->box<=12)?1:(G*6))  /* Amount of rounding. */
224#define RT ((sp->box<=12)?1:(G*3)) /* Thickness of wall of rounded parts.
225                                      Here 3 is an approximation to 2 sqrt(2). */
226#define RR 0   /* Roof ridge thickness */
227
228#if 0
229/* A list of those bitmaps we need to create to display any pentomino. */
230/* (not used right now because it does not seem to work for hexonimoes.) */
231
232static int bitmaps_needed[] =
233{
234 LEFT_UP|LEFT_DOWN|RIGHT_UP|RIGHT_DOWN,
235
236 LEFT|RIGHT_UP|RIGHT_DOWN,
237 RIGHT|LEFT_UP|LEFT_DOWN,
238 UP|LEFT_DOWN|RIGHT_DOWN,
239 DOWN|LEFT_UP|RIGHT_UP,
240 LEFT|RIGHT_UP,
241 RIGHT|LEFT_UP,
242 UP|LEFT_DOWN,
243 DOWN|LEFT_UP,
244 LEFT|RIGHT_DOWN,
245 RIGHT|LEFT_DOWN,
246 UP|RIGHT_DOWN,
247 DOWN|RIGHT_UP,
248
249/* These needed for hexonimoes*/
250 LEFT,
251 RIGHT,
252 UP,
253 DOWN,
254 LEFT_DOWN|RIGHT_UP|RIGHT_DOWN,
255 LEFT_UP|RIGHT_UP|RIGHT_DOWN,
256 LEFT_UP|LEFT_DOWN|RIGHT_DOWN,
257 LEFT_UP|LEFT_DOWN|RIGHT_UP,
258
259 LEFT|UP|RIGHT_DOWN,
260 LEFT|DOWN|RIGHT_UP,
261 RIGHT|UP|LEFT_DOWN,
262 RIGHT|DOWN|LEFT_UP,
263 LEFT|UP,
264 LEFT|DOWN,
265 RIGHT|UP,
266 RIGHT|DOWN,
267
268 LEFT|RIGHT,
269 UP|DOWN,
270
271 RIGHT|UP|DOWN,
272 LEFT|UP|DOWN,
273 LEFT|RIGHT|DOWN,
274 LEFT|RIGHT|UP,
275
276 -1
277};
278
279static int bitmap_needed(int n) {
280  int i;
281
282  for (i=0;bitmaps_needed[i]!=-1;i++)
283    if (n == bitmaps_needed[i])
284      return 1;
285  return 0;
286}
287
288#endif
289
290/* Some debugging routines.
291
292static void print_board(polyominoesstruct *sp) {
293  int x,y;
294  for (y=0;y<sp->height;y++) {
295    for (x=0;x<sp->width;x++)
296      if (ARRAY(x,y) == -1)
297        fprintf(stderr," ");
298      else
299        fprintf(stderr,"%c",'a'+ARRAY(x,y));
300    fprintf(stderr,"\n");
301  }
302  fprintf(stderr,"\n");
303}
304
305static void print_points(point_type *point, int len) {
306  int i;
307
308  for (i=0;i<len;i++)
309    fprintf(stderr,"(%d %d) ",point[i].x,point[i].y);
310}
311
312static void print_polyomino(polyomino_type poly) {
313  int i;
314
315  print_points(poly.point,poly.len);
316  fprintf(stderr,"\n");
317  for (i=0;i<poly.transform_len;i++)
318    fprintf(stderr,"%d ",poly.transform_list[i]);
319  fprintf(stderr,"\n");
320}
321*/
322
323static polyominoesstruct *polyominoeses = (polyominoesstruct *) NULL;
324
325static
326void random_permutation(int n, int a[]) {
327  int i,j,k,r;
328
329  for (i=0;i<n;i++) a[i] = -1;
330  for (i=0;i<n;i++) {
331    r=NRAND(n-i);
332    k=0;
333    while(a[k]!=-1) k++;
334    for (j=0;j<r;j++) {
335      k++;
336      while(a[k]!=-1) k++;
337    }
338    a[k]=i;
339  }
340}
341
342
343/************************************************************
344These are the routines for manipulating the polyominoes and
345attaching and detaching them from the rectangle.
346************************************************************/
347
348static void transform(point_type in, point_type offset, int transform_no,
349                      point_type attach_point, point_type *out) {
350  switch (transform_no) {
351    case 0: out->x=in.x-offset.x+attach_point.x;
352            out->y=in.y-offset.y+attach_point.y;
353            break;
354    case 1: out->x=-(in.y-offset.y)+attach_point.x;
355            out->y=in.x-offset.x+attach_point.y;
356            break;
357    case 2: out->x=-(in.x-offset.x)+attach_point.x;
358            out->y=-(in.y-offset.y)+attach_point.y;
359            break;
360    case 3: out->x=in.y-offset.y+attach_point.x;
361            out->y=-(in.x-offset.x)+attach_point.y;
362            break;
363    case 4: out->x=-(in.x-offset.x)+attach_point.x;
364            out->y=in.y-offset.y+attach_point.y;
365            break;
366    case 5: out->x=in.y-offset.y+attach_point.x;
367            out->y=in.x-offset.x+attach_point.y;
368            break;
369    case 6: out->x=in.x-offset.x+attach_point.x;
370            out->y=-(in.y-offset.y)+attach_point.y;
371            break;
372    case 7: out->x=-(in.y-offset.y)+attach_point.x;
373            out->y=-(in.x-offset.x)+attach_point.y;
374            break;
375  }
376}
377
378static int first_poly_no(polyominoesstruct *sp) {
379  int poly_no;
380
381  poly_no = 0;
382  while(poly_no<sp->nr_polyominoes && sp->polyomino[poly_no].attached)
383    poly_no++;
384  return poly_no;
385}
386
387static void next_poly_no(polyominoesstruct *sp, int *poly_no) {
388
389  if (sp->identical) {
390    *poly_no = sp->nr_polyominoes;
391  } else {
392    do {
393      (*poly_no)++;
394    } while (*poly_no<sp->nr_polyominoes && sp->polyomino[*poly_no].attached);
395  }
396}
397
398/* check_all_regions_multiple_of looks for connected regions of
399   blank spaces, and returns 0 if it finds a connected region containing
400   a number of blanks that is not a multiple of n.
401*/
402
403static void count_adjacent_blanks(polyominoesstruct *sp, int *count, int x, int y, int blank_mark) {
404
405  if (ARRAY(x,y) == -1) {
406    (*count)++;
407    ARRAY(x,y) = blank_mark;
408    if (x>=1) count_adjacent_blanks(sp, count,x-1,y,blank_mark);
409    if (x<sp->width-1) count_adjacent_blanks(sp, count,x+1,y,blank_mark);
410    if (y>=1) count_adjacent_blanks(sp, count,x,y-1,blank_mark);
411    if (y<sp->height-1) count_adjacent_blanks(sp, count,x,y+1,blank_mark);
412  }
413}
414
415static int check_all_regions_multiple_of(polyominoesstruct *sp, int n) {
416  int x,y,count,good = 1;
417
418  for (x=0;x<sp->width && good;x++) for (y=0;y<sp->height && good;y++) {
419    count = 0;
420    count_adjacent_blanks(sp, &count,x,y,-2);
421    good = count%n == 0;
422  }
423
424  for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++)
425    if (ARRAY(x,y) == -2)
426      ARRAY(x,y) = -1;
427
428  return good;
429}
430
431static int check_all_regions_positive_combination_of(polyominoesstruct *sp, int m, int n) {
432  int x,y,count,good = 1;
433
434  for (x=0;x<sp->width && good;x++) for (y=0;y<sp->height && good;y++) {
435    count = 0;
436    count_adjacent_blanks(sp, &count,x,y,-2);
437    good = 0;
438    for (;count>=0 && !good;count-=m)
439      good = count%n == 0;
440  }
441
442  for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++)
443    if (ARRAY(x,y) == -2)
444      ARRAY(x,y) = -1;
445
446  return good;
447}
448
449static int find_smallest_blank_component(polyominoesstruct *sp) {
450  int x,y,size,smallest_size,blank_mark,smallest_mark;
451
452  smallest_mark = blank_mark = -10;
453  smallest_size = 1000000000;
454  for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) if (ARRAY(x,y) == -1) {
455    size = 0;
456    count_adjacent_blanks(sp, &size,x,y,blank_mark);
457    if (size<smallest_size) {
458      smallest_mark = blank_mark;
459      smallest_size = size;
460    }
461    blank_mark--;
462  }
463
464  return smallest_mark;
465}
466
467/* "Chess board" check - see init_max_whites_list above for more details.
468*/
469/* If the rectangle is alternatively covered by white and black
470   squares (chess board style), then this gives the list of
471   the maximal possible whites covered by each polyomino.  It
472   is used by the function whites_ok which makes sure that the
473   array has a valid number of white or black remaining blanks left.
474*/
475
476static int whites_ok(polyominoesstruct *sp) {
477  int x,y,poly_no,whites=0,blacks=0,max_white=0,min_white=0;
478
479  for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) {
480    if (ARRAY(x,y) == -1 && (x+y)%2) whites++;
481    if (ARRAY(x,y) == -1 && (x+y+1)%2) blacks++;
482  }
483  for (poly_no=0;poly_no<sp->nr_polyominoes;poly_no++) if (!sp->polyomino[poly_no].attached) {
484    max_white += sp->polyomino[poly_no].max_white;
485    min_white += sp->polyomino[poly_no].len - sp->polyomino[poly_no].max_white;
486  }
487  return (min_white <= blacks && min_white <= whites
488          && blacks <= max_white && whites <= max_white);
489}
490
491/* This routine looks at the point (x,y) and sees how many polyominoes
492   and all their various transforms may be attached there.
493*/
494
495static int
496score_point(polyominoesstruct *sp, int x, int y, int min_score_so_far) {
497  int poly_no, point_no, transform_index, i, attachable;
498  point_type attach_point, target_point;
499  int score = 0;
500
501  if (x>=1 && x<sp->width-1 && y>=1 && y<sp->height-1 &&
502      ARRAY(x-1,y-1)<0 && ARRAY(x-1,y)<0 && ARRAY(x-1,y+1)<0 &&
503      ARRAY(x+1,y-1)<0 && ARRAY(x+1,y)<0 && ARRAY(x+1,y+1)<0 &&
504      ARRAY(x,y-1)<0 && ARRAY(x,y+1)<0)
505    return 10000;
506
507  attach_point.x = x;
508  attach_point.y = y;
509  for (poly_no=first_poly_no(sp);poly_no<sp->nr_polyominoes;next_poly_no(sp,&poly_no))
510  if (!sp->polyomino[poly_no].attached) {
511    for (point_no=0;point_no<sp->polyomino[poly_no].len;point_no++)
512    for (transform_index=0;transform_index<sp->polyomino[poly_no].transform_len;transform_index++) {
513      attachable = 1;
514      for (i=0;i<sp->polyomino[poly_no].len;i++) {
515        transform(sp->polyomino[poly_no].point[i],
516                  sp->polyomino[poly_no].point[point_no],
517                  sp->polyomino[poly_no].transform_list[transform_index],
518                  attach_point, &target_point);
519        if ( ! ((target_point.x>=0) && (target_point.x<sp->width)
520                  && (target_point.y>=0) && (target_point.y<sp->height)
521                  && (ARRAY_P(target_point)<0))) {
522          attachable = 0;
523          break;
524        }
525      }
526      if (attachable) {
527        score++;
528        if (score>=min_score_so_far)
529          return score;
530      }
531    }
532  }
533
534  return score;
535}
536
537static void find_blank(polyominoesstruct *sp, point_type *point) {
538  int score, worst_score;
539  int x, y;
540  int blank_mark;
541
542  blank_mark = find_smallest_blank_component(sp);
543
544  worst_score = 1000000;
545  for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) if (ARRAY(x,y)==blank_mark) {
546    score = 100*score_point(sp,x,y,worst_score);
547    if (score>0) {
548      if (sp->left_right) score += 10*x;
549      else                score += 10*(sp->width-1-x);
550      if (sp->top_bottom) score += y;
551      else                score += (sp->height-1-y);
552    }
553    if (score<worst_score) {
554      point->x = x;
555      point->y = y;
556      worst_score = score;
557    }
558  }
559
560  for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++)
561    if (ARRAY(x,y)<0) ARRAY(x,y) = -1;
562}
563
564/* Detaches the most recently attached polyomino. */
565
566static
567void detach(polyominoesstruct *sp, int *poly_no, int *point_no, int *transform_index, point_type *attach_point, int rot180) {
568  int i;
569  point_type target_point;
570
571  if (sp->nr_attached == 0) return;
572  sp->nr_attached--;
573  *poly_no = sp->attach_list[sp->nr_attached];
574  *point_no = sp->polyomino[*poly_no].point_no;
575  *transform_index = sp->polyomino[*poly_no].transform_index;
576  *attach_point = sp->polyomino[*poly_no].attach_point;
577  for (i=0;i<sp->polyomino[*poly_no].len;i++) {
578    transform(sp->polyomino[*poly_no].point[i],
579              sp->polyomino[*poly_no].point[*point_no],
580              sp->polyomino[*poly_no].transform_list[*transform_index]^(rot180<<1),
581              *attach_point, &target_point);
582    ARRAY_P(target_point) = -1;
583    CHANGED_ARRAY_P(target_point) = 1;
584  }
585
586  sp->polyomino[*poly_no].attached = 0;
587}
588
589/* Attempts to attach a polyomino at point (x,y) at the
590   point_no-th point of that polyomino, using the transform
591   transform_no.  Returns 1 if successful.
592*/
593
594static
595int attach(polyominoesstruct *sp, int poly_no, int point_no, int transform_index, point_type attach_point, int rot180,
596           int *reason_to_not_attach) {
597  point_type target_point;
598  int i;
599  int attachable = 1, worst_reason_not_to_attach = 1000000000;
600
601  if (rot180) {
602    attach_point.x = sp->width-1-attach_point.x;
603    attach_point.y = sp->height-1-attach_point.y;
604  }
605
606  if (sp->polyomino[poly_no].attached)
607    return 0;
608
609  for (i=0;i<sp->polyomino[poly_no].len;i++) {
610    transform(sp->polyomino[poly_no].point[i],
611              sp->polyomino[poly_no].point[point_no],
612              sp->polyomino[poly_no].transform_list[transform_index]^(rot180<<1),
613              attach_point, &target_point);
614    if ( ! ((target_point.x>=0) && (target_point.x<sp->width)
615              && (target_point.y>=0) && (target_point.y<sp->height)
616              && (ARRAY_P(target_point) == -1))) {
617      if (sp->identical) {
618        attachable = 0;
619        if ((target_point.x>=0) && (target_point.x<sp->width)
620           && (target_point.y>=0) && (target_point.y<sp->height)
621           && (ARRAY_P(target_point) >= 0)
622           && (ARRAY_P(target_point)<worst_reason_not_to_attach))
623          worst_reason_not_to_attach = ARRAY_P(target_point);
624      }
625      else
626        return 0;
627    }
628  }
629
630  if (sp->identical && !attachable) {
631    if (worst_reason_not_to_attach < 1000000000)
632      reason_to_not_attach[worst_reason_not_to_attach] = 1;
633    return 0;
634  }
635
636  for (i=0;i<sp->polyomino[poly_no].len;i++) {
637    transform(sp->polyomino[poly_no].point[i],
638              sp->polyomino[poly_no].point[point_no],
639              sp->polyomino[poly_no].transform_list[transform_index]^(rot180<<1),
640              attach_point, &target_point);
641    ARRAY_P(target_point) = poly_no;
642    CHANGED_ARRAY_P(target_point) = 1;
643  }
644
645  sp->attach_list[sp->nr_attached] = poly_no;
646  sp->nr_attached++;
647
648  sp->polyomino[poly_no].attached = 1;
649  sp->polyomino[poly_no].point_no = point_no;
650  sp->polyomino[poly_no].attach_point = attach_point;
651  sp->polyomino[poly_no].transform_index = transform_index;
652
653  if (!sp->check_ok(sp)) {
654    detach(sp,&poly_no,&point_no,&transform_index,&attach_point,rot180);
655    return 0;
656  }
657
658  return 1;
659}
660
661static
662int next_attach_try(polyominoesstruct *sp, int *poly_no, int *point_no, int *transform_index) {
663
664  (*transform_index)++;
665  if (*transform_index>=sp->polyomino[*poly_no].transform_len) {
666    *transform_index = 0;
667    (*point_no)++;
668    if (*point_no>=sp->polyomino[*poly_no].len) {
669      *point_no = 0;
670      next_poly_no(sp,poly_no);
671      if (*poly_no>=sp->nr_polyominoes) {
672        *poly_no = first_poly_no(sp);
673        return 0;
674      }
675    }
676  }
677  return 1;
678}
679
680
681/*******************************************************
682Display routines.
683*******************************************************/
684
685static void
686draw_without_bitmaps(ModeInfo * mi, polyominoesstruct *sp) {
687  Display *display = MI_DISPLAY(mi);
688  Window  window = MI_WINDOW(mi);
689  GC gc = MI_GC(mi);
690  int x,y,poly_no,nr_lines,nr_rectangles;
691
692  XSetLineAttributes(display,gc,sp->box/10+1,LineSolid,CapRound,JoinRound);
693
694  for (poly_no=-1;poly_no<sp->nr_polyominoes;poly_no++) {
695    nr_rectangles = 0;
696    for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++)
697    if (CHANGED_ARRAY(x,y) && ARRAY(x,y) == poly_no) {
698      sp->rectangles[nr_rectangles].x = sp->x_margin + sp->box*x;
699      sp->rectangles[nr_rectangles].y = sp->y_margin + sp->box*y;
700      sp->rectangles[nr_rectangles].width = sp->box;
701      sp->rectangles[nr_rectangles].height = sp->box;
702      nr_rectangles++;
703    }
704    if (poly_no == -1)
705      XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
706    else
707      XSetForeground(display, gc, sp->polyomino[poly_no].color);
708    XFillRectangles(display, window, gc, sp->rectangles, nr_rectangles);
709  }
710
711  XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
712
713  nr_lines = 0;
714  for (x=0;x<sp->width-1;x++) for (y=0;y<sp->height;y++) {
715    if (ARRAY(x,y) == -1 && ARRAY(x+1,y) == -1
716        && (CHANGED_ARRAY(x,y) || CHANGED_ARRAY(x+1,y))) {
717      sp->lines[nr_lines].x1 = sp->x_margin + sp->box*(x+1);
718      sp->lines[nr_lines].y1 = sp->y_margin + sp->box*y;
719      sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1);
720      sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1);
721      nr_lines++;
722    }
723  }
724  XDrawSegments(display, window, gc, sp->lines, nr_lines);
725
726  nr_lines = 0;
727  for (x=0;x<sp->width;x++) for (y=0;y<sp->height-1;y++) {
728    if (ARRAY(x,y) == -1 && ARRAY(x,y+1) == -1
729        && (CHANGED_ARRAY(x,y) || CHANGED_ARRAY(x,y+1))) {
730      sp->lines[nr_lines].x1 = sp->x_margin + sp->box*x;
731      sp->lines[nr_lines].y1 = sp->y_margin + sp->box*(y+1);
732      sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1);
733      sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1);
734      nr_lines++;
735    }
736  }
737  XDrawSegments(display, window, gc, sp->lines, nr_lines);
738
739  XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
740  XDrawRectangle(display, window, gc, sp->x_margin, sp->y_margin, sp->box*sp->width, sp->box*sp->height);
741
742  XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
743
744  nr_lines = 0;
745  for (x=0;x<sp->width-1;x++) for (y=0;y<sp->height;y++) {
746    if (ARRAY(x+1,y) != ARRAY(x,y)) {
747      sp->lines[nr_lines].x1 = sp->x_margin + sp->box*(x+1);
748      sp->lines[nr_lines].y1 = sp->y_margin + sp->box*y;
749      sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1);
750      sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1);
751      nr_lines++;
752    }
753  }
754  XDrawSegments(display, window, gc, sp->lines, nr_lines);
755
756  nr_lines = 0;
757  for (x=0;x<sp->width;x++) for (y=0;y<sp->height-1;y++) {
758    if (ARRAY(x,y+1) != ARRAY(x,y)) {
759      sp->lines[nr_lines].x1 = sp->x_margin + sp->box*x;
760      sp->lines[nr_lines].y1 = sp->y_margin + sp->box*(y+1);
761      sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1);
762      sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1);
763      nr_lines++;
764    }
765  }
766  XDrawSegments(display, window, gc, sp->lines, nr_lines);
767  XSetLineAttributes(display,gc,1,LineSolid,CapRound,JoinRound);
768  XFlush(display);
769}
770
771static void create_bitmaps(ModeInfo * mi, polyominoesstruct *sp) {
772  int x,y,n;
773  char *data;
774
775  for (n=0;n<256;n++) {
776
777/* Avoid duplication of identical bitmaps. */
778    if (IS_LEFT_UP(n) && (IS_LEFT(n) || IS_UP(n)))
779      sp->bitmaps[n] = sp->bitmaps[n & ~LEFT_UP];
780    else if (IS_LEFT_DOWN(n) && (IS_LEFT(n) || IS_DOWN(n)))
781      sp->bitmaps[n] = sp->bitmaps[n & ~LEFT_DOWN];
782    else if (IS_RIGHT_UP(n) && (IS_RIGHT(n) || IS_UP(n)))
783      sp->bitmaps[n] = sp->bitmaps[n & ~RIGHT_UP];
784    else if (IS_RIGHT_DOWN(n) && (IS_RIGHT(n) || IS_DOWN(n)))
785      sp->bitmaps[n] = sp->bitmaps[n & ~RIGHT_DOWN];
786
787    else /* if (bitmap_needed(n)) */ {
788      data = (char *) malloc(sizeof(char)*(sp->box*ROUND8(sp->box)/8));
789      if (data == NULL) {
790        sp->use_bitmaps = 0;
791        return;
792      }
793
794      for (y=0;y<sp->box;y++) for (x=0;x<sp->box;x++) {
795        if (!sp->use3D) {
796#ifdef SMALL_BELLYBUTTON
797          if (x >= sp->box / 2 && x <= sp->box / 2 + 1 &&
798              y >= sp->box / 2 && y <= sp->box / 2 + 1)
799            NOTHALFBIT(n,x,y)
800          else
801#endif
802            HALFBIT(n,x,y)
803        } else if ((x>=y && x<=sp->box-y-1 && IS_UP(n))
804            || (x<=y && x<=sp->box-y-1 && y<sp->box/2 && !IS_LEFT(n))
805            || (x>=y && x>=sp->box-y-1 && y<sp->box/2 && !IS_RIGHT(n)))
806          SETBIT(n,x,y)
807        else if ((x<=y && x<=sp->box-y-1 && IS_LEFT(n))
808            || (x>=y && x<=sp->box-y-1 && x<sp->box/2 && !IS_UP(n))
809            || (x<=y && x>=sp->box-y-1 && x<sp->box/2 && !IS_DOWN(n)))
810          TWOTHIRDSBIT(n,x,y)
811        else if ((x>=y && x>=sp->box-y-1 && IS_RIGHT(n))
812            || (x>=y && x<=sp->box-y-1 && x>=sp->box/2 && !IS_UP(n))
813            || (x<=y && x>=sp->box-y-1 && x>=sp->box/2 && !IS_DOWN(n)))
814          HALFBIT(n,x,y)
815        else if ((x<=y && x>=sp->box-y-1 && IS_DOWN(n))
816            || (x<=y && x<=sp->box-y-1 && y>=sp->box/2 && !IS_LEFT(n))
817            || (x>=y && x>=sp->box-y-1 && y>=sp->box/2 && !IS_RIGHT(n)))
818          THIRDBIT(n,x,y)
819      }
820
821      if (IS_LEFT(n))
822        for (y=0;y<sp->box;y++) for (x=G;x<G+T;x++)
823          SETBIT(n,x,y)
824      if (IS_RIGHT(n))
825        for (y=0;y<sp->box;y++) for (x=G;x<G+T;x++)
826          SETBIT(n,sp->box-1-x,y)
827      if (IS_UP(n))
828        for (x=0;x<sp->box;x++) for (y=G;y<G+T;y++)
829          SETBIT(n,x,y)
830      if (IS_DOWN(n))
831        for (x=0;x<sp->box;x++) for (y=G;y<G+T;y++)
832          SETBIT(n,x,sp->box-1-y)
833      if (IS_LEFT(n))
834        for (y=0;y<sp->box;y++) for (x=0;x<G;x++)
835          RESBIT(n,x,y)
836      if (IS_RIGHT(n))
837        for (y=0;y<sp->box;y++) for (x=0;x<G;x++)
838          RESBIT(n,sp->box-1-x,y)
839      if (IS_UP(n))
840        for (x=0;x<sp->box;x++) for (y=0;y<G;y++)
841          RESBIT(n,x,y)
842      if (IS_DOWN(n))
843        for (x=0;x<sp->box;x++) for (y=0;y<G;y++)
844          RESBIT(n,x,sp->box-1-y)
845
846      if (IS_LEFT(n) && IS_UP(n))
847        for (x=G;x<=G+R;x++)
848          for (y=G;y<=R+2*G-x;y++) {
849            if (x+y>R+2*G-RT)
850              SETBIT(n,x,y)
851            else
852              RESBIT(n,x,y)
853          }
854      if (IS_LEFT(n) && IS_DOWN(n))
855        for (x=G;x<=G+R;x++)
856          for (y=G;y<=R+2*G-x;y++) {
857            if (x+y>R+2*G-RT)
858              SETBIT(n,x,sp->box-1-y)
859            else
860              RESBIT(n,x,sp->box-1-y)
861          }
862      if (IS_RIGHT(n) && IS_UP(n))
863        for (x=G;x<=G+R;x++)
864          for (y=G;y<=R+2*G-x;y++) {
865            if (x+y>R+2*G-RT)
866              SETBIT(n,sp->box-1-x,y)
867            else
868              RESBIT(n,sp->box-1-x,y)
869          }
870      if (IS_RIGHT(n) && IS_DOWN(n))
871        for (x=G;x<=G+R;x++)
872          for (y=G;y<=R+2*G-x;y++) {
873            if (x+y>R+2*G-RT)
874              SETBIT(n,sp->box-1-x,sp->box-1-y)
875            else
876              RESBIT(n,sp->box-1-x,sp->box-1-y)
877          }
878
879      if (!IS_LEFT(n) && !IS_UP(n) && IS_LEFT_UP(n)) {
880        for (x=0;x<G;x++) for(y=0;y<G;y++)
881          RESBIT(n,x,y)
882        for (x=G;x<G+T;x++) for(y=0;y<G;y++)
883          SETBIT(n,x,y)
884        for (x=0;x<G+T;x++) for(y=G;y<G+T;y++)
885          SETBIT(n,x,y)
886      }
887      if (!IS_LEFT(n) && !IS_DOWN(n) && IS_LEFT_DOWN(n)) {
888        for (x=0;x<G;x++) for(y=0;y<G;y++)
889          RESBIT(n,x,sp->box-1-y)
890        for (x=G;x<G+T;x++) for(y=0;y<G;y++)
891          SETBIT(n,x,sp->box-1-y)
892        for (x=0;x<G+T;x++) for(y=G;y<G+T;y++)
893          SETBIT(n,x,sp->box-1-y)
894      }
895      if (!IS_RIGHT(n) && !IS_UP(n) && IS_RIGHT_UP(n)) {
896        for (x=0;x<G;x++) for(y=0;y<G;y++)
897          RESBIT(n,sp->box-1-x,y)
898        for (x=G;x<G+T;x++) for(y=0;y<G;y++)
899          SETBIT(n,sp->box-1-x,y)
900        for (x=0;x<G+T;x++) for(y=G;y<G+T;y++)
901          SETBIT(n,sp->box-1-x,y)
902      }
903      if (!IS_RIGHT(n) && !IS_DOWN(n) && IS_RIGHT_DOWN(n)) {
904        for (x=0;x<G;x++) for(y=0;y<G;y++)
905          RESBIT(n,sp->box-1-x,sp->box-1-y)
906        for (x=G;x<G+T;x++) for(y=0;y<G;y++)
907          SETBIT(n,sp->box-1-x,sp->box-1-y)
908        for (x=0;x<G+T;x++) for(y=G;y<G+T;y++)
909          SETBIT(n,sp->box-1-x,sp->box-1-y)
910      }
911
912#ifdef LARGE_BELLYBUTTON
913      if (!sp->use3D) {
914        if (!IS_LEFT(n) && !IS_UP(n) && !IS_LEFT_UP(n))
915          for (x=0;x<G+T;x++) for(y=0;y<G+T;y++)
916            SETBIT(n,x,y)
917        if (!IS_LEFT(n) && !IS_DOWN(n) && !IS_LEFT_DOWN(n))
918          for (x=0;x<G+T;x++) for(y=sp->box-G-T;y<sp->box;y++)
919            SETBIT(n,x,y)
920        if (!IS_RIGHT(n) && !IS_UP(n) && !IS_RIGHT_UP(n))
921          for (x=sp->box-G-T;x<sp->box;x++) for(y=0;y<G+T;y++)
922            SETBIT(n,x,y)
923        if (!IS_RIGHT(n) && !IS_DOWN(n) && !IS_RIGHT_DOWN(n))
924          for (x=sp->box-G-T;x<sp->box;x++) for(y=sp->box-G-T;y<sp->box;y++)
925            SETBIT(n,x,y)
926      } else
927#else
928      if (sp->use3D)
929#endif
930      {
931        if (!IS_LEFT(n) && !IS_UP(n) && !IS_LEFT_UP(n))
932          for (x=0;x<sp->box/2-RR;x++) for(y=0;y<sp->box/2-RR;y++)
933            THREEQUARTERSBIT(n,x,y)
934        if (!IS_LEFT(n) && !IS_DOWN(n) && !IS_LEFT_DOWN(n))
935          for (x=0;x<sp->box/2-RR;x++) for(y=sp->box/2+RR;y<sp->box;y++)
936            THREEQUARTERSBIT(n,x,y)
937        if (!IS_RIGHT(n) && !IS_UP(n) && !IS_RIGHT_UP(n))
938          for (x=sp->box/2+RR;x<sp->box;x++) for(y=0;y<sp->box/2-RR;y++)
939            THREEQUARTERSBIT(n,x,y)
940        if (!IS_RIGHT(n) && !IS_DOWN(n) && !IS_RIGHT_DOWN(n))
941          for (x=sp->box/2+RR;x<sp->box;x++) for(y=sp->box/2+RR;y<sp->box;y++)
942            THREEQUARTERSBIT(n,x,y)
943      }
944
945      sp->bitmaps[n] = XCreateImage(MI_DISPLAY(mi), MI_VISUAL(mi), 1, XYBitmap,
946                                    0, data, sp->box, sp->box, 8, 0);
947      if (sp->bitmaps[n] == None) {
948        free(data);
949        sp->use_bitmaps = 0;
950        return;
951      }
952      sp->bitmaps[n]->byte_order = MSBFirst;
953      sp->bitmaps[n]->bitmap_unit = 8;
954      sp->bitmaps[n]->bitmap_bit_order = LSBFirst;
955    }
956  }
957
958  sp->use_bitmaps = 1;
959}
960
961static void draw_with_bitmaps(ModeInfo * mi, polyominoesstruct *sp) {
962  Display *display = MI_DISPLAY(mi);
963  Window  window = MI_WINDOW(mi);
964  GC gc = MI_GC(mi);
965  int x,y,t,bitmap_index;
966
967  for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) {
968    if (ARRAY(x,y) == -1) {
969      if (CHANGED_ARRAY(x,y)) {
970        XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
971        XFillRectangle(display,window,gc,
972                       sp->x_margin + sp->box*x,
973                       sp->y_margin + sp->box*y,
974                       sp->box,sp->box);
975      }
976    }
977    else {
978      XSetForeground(display, gc, sp->polyomino[ARRAY(x,y)].color);
979      bitmap_index = 0;
980      if (ARR(x,y) != ARR(x-1,y))   bitmap_index |= LEFT;
981      if (ARR(x,y) != ARR(x+1,y))   bitmap_index |= RIGHT;
982      if (ARR(x,y) != ARR(x,y-1))   bitmap_index |= UP;
983      if (ARR(x,y) != ARR(x,y+1))   bitmap_index |= DOWN;
984      if (ARR(x,y) != ARR(x-1,y-1)) bitmap_index |= LEFT_UP;
985      if (ARR(x,y) != ARR(x-1,y+1)) bitmap_index |= LEFT_DOWN;
986      if (ARR(x,y) != ARR(x+1,y-1)) bitmap_index |= RIGHT_UP;
987      if (ARR(x,y) != ARR(x+1,y+1)) bitmap_index |= RIGHT_DOWN;
988      (void) XPutImage(display,window,gc,
989                sp->bitmaps[bitmap_index],
990                0,0,
991                sp->x_margin + sp->box*x,
992                sp->y_margin + sp->box*y,
993                sp->box,sp->box);
994    }
995  }
996
997  XSetForeground(display, gc, sp->border_color);
998  for (t=G;t<G+T;t++)
999    XDrawRectangle(display,window,gc,
1000                   sp->x_margin-t-1,sp->y_margin-t-1,
1001                   sp->box*sp->width+1+2*t, sp->box*sp->height+1+2*t);
1002  XFlush(display);
1003}
1004
1005
1006/***************************************************
1007Routines to initialise and close down polyominoes.
1008***************************************************/
1009
1010static void free_bitmaps(polyominoesstruct *sp) {
1011  int n;
1012 
1013  for (n=0;n<256;n++)
1014/* Don't bother to free duplicates */
1015    if (IS_LEFT_UP(n) && (IS_LEFT(n) || IS_UP(n)))
1016      sp->bitmaps[n] = None;
1017    else if (IS_LEFT_DOWN(n) && (IS_LEFT(n) || IS_DOWN(n)))
1018      sp->bitmaps[n] = None;
1019    else if (IS_RIGHT_UP(n) && (IS_RIGHT(n) || IS_UP(n)))
1020      sp->bitmaps[n] = None;
1021    else if (IS_RIGHT_DOWN(n) && (IS_RIGHT(n) || IS_DOWN(n)))
1022      sp->bitmaps[n] = None;
1023
1024    else if (sp->bitmaps[n] != None) {
1025        XDestroyImage(sp->bitmaps[n]);
1026        sp->bitmaps[n] = None;
1027    }
1028}
1029
1030#define deallocate(p,t) if ((p)!=NULL) {free(p); p=(t*)NULL;}
1031
1032static void free_polyominoes(polyominoesstruct *sp) {
1033  int n;
1034
1035  for (n=0;n<sp->nr_polyominoes;n++) {
1036    deallocate(sp->polyomino[n].point, point_type);
1037  }
1038
1039  deallocate(sp->polyomino, polyomino_type);
1040  deallocate(sp->attach_list, int);
1041  deallocate(sp->rectangles, XRectangle);
1042  deallocate(sp->lines, XSegment);
1043  deallocate(sp->reason_to_not_attach, int);
1044  deallocate(sp->array, int);
1045  deallocate(sp->changed_array, int);
1046
1047  free_bitmaps(sp);
1048}
1049
1050#define set_allocate(p,type,size) p = (type *) malloc(size);            \
1051                             if ((p)==NULL) {free_polyominoes(sp);return 0;}
1052
1053#define copy_polyomino(dst,src,new_rand)                                \
1054  (dst).len=(src).len;                                                  \
1055  (dst).max_white = (src).max_white;                                    \
1056  set_allocate((dst).point,point_type,sizeof(point_type)*(src).len);            \
1057  (dst).len = (src).len;                                                \
1058  if (new_rand)                                                         \
1059    random_permutation((src).len,perm_point);                           \
1060  for (i=0;i<(src).len;i++)                                             \
1061    (dst).point[i] = (src).point[perm_point[i]];                        \
1062  (dst).transform_len = (src).transform_len;                            \
1063  if (new_rand)                                                         \
1064    random_permutation((src).transform_len,perm_transform);             \
1065  for (i=0;i<(src).transform_len;i++)                                   \
1066    (dst).transform_list[i] = (src).transform_list[perm_transform[i]];  \
1067  (dst).attached = 0
1068
1069
1070/***************************************************
1071Puzzle specific initialization routines.
1072***************************************************/
1073
1074static
1075int check_pentomino_puzzle(polyominoesstruct *sp) {
1076  return check_all_regions_multiple_of(sp, 5) && whites_ok(sp);
1077}
1078
1079static
1080int check_hexomino_puzzle(polyominoesstruct *sp) {
1081  return check_all_regions_multiple_of(sp, 6) && whites_ok(sp);
1082}
1083
1084static
1085int check_tetr_pentomino_puzzle(polyominoesstruct *sp) {
1086  return check_all_regions_positive_combination_of(sp, 5, 4) && whites_ok(sp);
1087}
1088
1089static
1090int check_pent_hexomino_puzzle(polyominoesstruct *sp) {
1091  return check_all_regions_positive_combination_of(sp, 6, 5) && whites_ok(sp);
1092}
1093
1094static
1095int check_heptomino_puzzle(polyominoesstruct *sp) {
1096  return check_all_regions_multiple_of(sp, 7) && whites_ok(sp);
1097}
1098
1099static
1100int check_octomino_puzzle(polyominoesstruct *sp) {
1101  return check_all_regions_multiple_of(sp, 8) && whites_ok(sp);
1102}
1103
1104static
1105int check_dekomino_puzzle(polyominoesstruct *sp) {
1106  return check_all_regions_multiple_of(sp, 10) && whites_ok(sp);
1107}
1108
1109static
1110int check_elevenomino_puzzle(polyominoesstruct *sp) {
1111  return check_all_regions_multiple_of(sp, 11) && whites_ok(sp);
1112}
1113
1114static struct {int len; point_type point[4];
1115               int transform_len, transform_list[8], max_white;} tetromino[5] =
1116{
1117/*
1118xxxx
1119*/
1120  {4, {{0,0}, {1,0}, {2,0}, {3,0}},
1121   2, {0, 1, -1, -1, -1, -1, -1, -1}, 2},
1122/*
1123xxx 
1124  x 
1125*/
1126  {4, {{0,0}, {1,0}, {2,0}, {2,1}},
1127   8, {0, 1, 2, 3, 4, 5, 6, 7}, 2},
1128/*
1129xxx 
1130 x   
1131*/
1132  {4, {{0,0}, {1,0}, {1,1}, {2,0}},
1133   4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1134/*
1135xx   
1136 xx 
1137*/
1138  {4, {{0,0}, {1,0}, {1,1}, {2,1}},
1139   4, {0, 1, 4, 5, -1, -1, -1, -1}, 2},
1140/*
1141xx   
1142xx   
1143*/
1144  {4, {{0,0}, {0,1}, {1,0}, {1,1}},
1145   1, {0, -1, -1, -1, -1, -1, -1, -1}, 2}};
1146
1147
1148static struct pentomino_struct {int len; point_type point[5];
1149                                int transform_len, transform_list[8], max_white;}
1150  pentomino[12] =
1151{
1152/*
1153xxxxx
1154*/
1155  {5, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}},
1156   2, {0, 1, -1, -1, -1, -1, -1, -1}, 3},
1157/*
1158xxxx 
1159   x 
1160*/
1161  {5, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}},
1162   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1163/*
1164xxxx 
1165  x   
1166*/
1167  {5, {{0,0}, {1,0}, {2,0}, {2,1}, {3,0}},
1168   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1169/*
1170  x   
1171xxx   
1172  x   
1173*/
1174  {5, {{0,0}, {1,0}, {2,-1}, {2,0}, {2,1}},
1175   4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1176/*
1177xxx   
1178  xx 
1179*/
1180  {5, {{0,0}, {1,0}, {2,0}, {2,1}, {3,1}},
1181   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1182/*
1183xxx   
1184 xx   
1185*/
1186  {5, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}},
1187   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1188/*
1189xxx   
1190  x   
1191  x   
1192*/
1193  {5, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}},
1194   4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1195/*
1196 x   
1197xxx   
1198  x   
1199*/
1200  {5, {{0,0}, {1,-1}, {1,0}, {2,0}, {2,1}},
1201   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1202/*
1203xxx   
1204x x   
1205*/
1206  {5, {{0,0}, {0,1}, {1,0}, {2,0}, {2,1}},
1207   4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1208/*
1209  x   
1210xxx   
1211x     
1212*/
1213  {5, {{0,0}, {0,1}, {1,0}, {2,-1}, {2,0}},
1214   4, {0, 1, 4, 5, -1, -1, -1, -1}, 3},
1215/*
1216 x   
1217xxx   
1218 x   
1219*/
1220  {5, {{0,0}, {1,-1}, {1,0}, {1,1}, {2,0}},
1221   1, {0, -1, -1, -1, -1, -1, -1, -1}, 4},
1222/*
1223xx   
1224 xx   
1225  x   
1226*/
1227  {5, {{0,0}, {1,0}, {1,1}, {2,1}, {2,2}},
1228   4, {0, 1, 2, 3, -1, -1, -1, -1}, 3}};
1229
1230
1231static struct hexomino_struct {int len; point_type point[6];
1232                               int transform_len, transform_list[8], max_white;}
1233  hexomino[35] =
1234{
1235/*
1236xxxxxx
1237*/
1238  {6, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {5,0}},
1239   2, {0, 1, -1, -1, -1, -1, -1, -1}, 3},
1240/*
1241xxxxx 
1242    x 
1243*/
1244  {6, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {4,1}},
1245   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1246/*
1247xxxxx 
1248   x   
1249*/
1250  {6, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}, {4,0}},
1251   8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
1252/*
1253xxxxx 
1254  x   
1255*/
1256  {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,0}, {4,0}},
1257   4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1258/*
1259   x   
1260xxxx   
1261   x   
1262*/
1263  {6, {{0,0}, {1,0}, {2,0}, {3,-1}, {3,0}, {3,1}},
1264   4, {0, 1, 2, 3, -1, -1, -1, -1}, 4},
1265/*
1266xxxx   
1267   xx 
1268*/
1269  {6, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}, {4,1}},
1270   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1271/*
1272xxxx   
1273  xx   
1274*/
1275  {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,0}, {3,1}},
1276   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1277/*
1278xxxx   
1279   x   
1280   x   
1281*/
1282  {6, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}, {3,2}},
1283   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1284/*
1285  x   
1286xxxx   
1287   x   
1288*/
1289  {6, {{0,0}, {1,0}, {2,-1}, {2,0}, {3,0}, {3,1}},
1290   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1291/*
1292xxxx   
1293 x x   
1294*/
1295  {6, {{0,0}, {1,0}, {1,1}, {2,0}, {3,0}, {3,1}},
1296   8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
1297/*
1298 x     
1299xxxx   
1300   x   
1301*/
1302  {6, {{0,0}, {1,-1}, {1,0}, {2,0}, {3,0}, {3,1}},
1303   8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
1304/*
1305xxxx   
1306x  x   
1307*/
1308  {6, {{0,0}, {0,1}, {1,0}, {2,0}, {3,0}, {3,1}},
1309   4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1310/*
1311   x   
1312xxxx   
1313x     
1314*/
1315  {6, {{0,0}, {0,1}, {1,0}, {2,0}, {3,-1}, {3,0}},
1316   4, {0, 1, 4, 5, -1, -1, -1, -1}, 3},
1317/*
1318  x   
1319xxxx   
1320  x   
1321*/
1322  {6, {{0,0}, {1,0}, {2,-1}, {2,0}, {2,1}, {3,0}},
1323   4, {0, 1, 2, 3, -1, -1, -1, -1}, 4},
1324/*
1325xxxx   
1326 xx   
1327*/
1328  {6, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}, {3,0}},
1329   4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1330/*
1331xxxx   
1332  x   
1333  x   
1334*/
1335  {6, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}, {3,0}},
1336   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1337/*
1338 x     
1339xxxx   
1340  x   
1341*/
1342  {6, {{0,0}, {1,-1}, {1,0}, {2,0}, {2,1}, {3,0}},
1343   4, {0, 1, 4, 5, -1, -1, -1, -1}, 3},
1344/*
1345  xx   
1346xxx   
1347  x   
1348*/
1349  {6, {{0,0}, {1,0}, {2,-1}, {2,0}, {2,1}, {3,-1}},
1350   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1351/*
1352 xx   
1353xxx   
1354  x   
1355*/
1356  {6, {{0,0}, {1,-1}, {1,0}, {2,-1}, {2,0}, {2,1}},
1357   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1358/*
1359  x   
1360xxx   
1361x x   
1362*/
1363  {6, {{0,0}, {0,1}, {1,0}, {2,-1}, {2,0}, {2,1}},
1364   8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
1365/*
1366xxx   
1367  xxx 
1368*/
1369  {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,1}, {4,1}},
1370   4, {0, 1, 4, 5, -1, -1, -1, -1}, 3},
1371/*
1372xxx   
1373  xx   
1374   x   
1375*/
1376  {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,1}, {3,2}},
1377   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1378/*
1379xxx   
1380 xxx   
1381*/
1382  {6, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}, {3,1}},
1383   4, {0, 1, 4, 5, -1, -1, -1, -1}, 4},
1384/*
1385xxx   
1386  xx   
1387  x   
1388*/
1389  {6, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}, {3,1}},
1390   8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
1391/*
1392 x     
1393xxx   
1394  xx   
1395*/
1396  {6, {{0,0}, {1,-1}, {1,0}, {2,0}, {2,1}, {3,1}},
1397   8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
1398/*
1399xxx   
1400x xx   
1401*/
1402  {6, {{0,0}, {0,1}, {1,0}, {2,0}, {2,1}, {3,1}},
1403   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1404/*
1405xxx   
1406 xx   
1407  x   
1408*/
1409  {6, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}, {2,2}},
1410   4, {0, 1, 2, 3, -1, -1, -1, -1}, 4},
1411/*
1412 x     
1413xxx   
1414 xx   
1415*/
1416  {6, {{0,0}, {1,-1}, {1,0}, {1,1}, {2,0}, {2,1}},
1417   4, {0, 1, 2, 3, -1, -1, -1, -1}, 4},
1418/*
1419xxx   
1420xxx   
1421*/
1422  {6, {{0,0}, {0,1}, {1,0}, {1,1}, {2,0}, {2,1}},
1423   2, {0, 1, -1, -1, -1, -1, -1, -1}, 3},
1424/*
1425xxx   
1426  x   
1427  xx   
1428*/
1429  {6, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}, {3,2}},
1430   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1431/*
1432xxx   
1433  x   
1434 xx   
1435*/
1436  {6, {{0,0}, {1,0}, {1,2}, {2,0}, {2,1}, {2,2}},
1437   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1438/*
1439 x     
1440xxx   
1441x x   
1442*/
1443  {6, {{0,0}, {0,1}, {1,-1}, {1,0}, {2,0}, {2,1}},
1444   4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1445/*
1446  xx   
1447xxx   
1448x     
1449*/
1450  {6, {{0,0}, {0,1}, {1,0}, {2,-1}, {2,0}, {3,-1}},
1451   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1452/*
1453 xx   
1454xxx   
1455x     
1456*/
1457  {6, {{0,0}, {0,1}, {1,-1}, {1,0}, {2,-1}, {2,0}},
1458   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1459/*
1460xx     
1461 xx   
1462  xx   
1463*/
1464  {6, {{0,0}, {1,0}, {1,1}, {2,1}, {2,2}, {3,2}},
1465   4, {0, 1, 4, 5, -1, -1, -1, -1}, 3}};
1466
1467static struct pentomino_struct one_sided_pentomino[60];
1468
1469void make_one_sided_pentomino(void) {
1470  int i,j,t,u;
1471
1472  j=0;
1473  for (i=0;i<18;i++) {
1474    one_sided_pentomino[j] = pentomino[i];
1475    for (t=0;t<8;t++)
1476      if (one_sided_pentomino[j].transform_list[t]>=4) {
1477        one_sided_pentomino[j].transform_len = t;
1478        j++;
1479        one_sided_pentomino[j] = pentomino[i];
1480        for (u=t;u<8;u++) one_sided_pentomino[j].transform_list[u-t] = one_sided_pentomino[j].transform_list[u];
1481        one_sided_pentomino[j].transform_len -= t;
1482        break;
1483      }
1484    j++;
1485  }
1486}
1487
1488static struct hexomino_struct one_sided_hexomino[60];
1489
1490void make_one_sided_hexomino(void) {
1491  int i,j,t,u;
1492
1493  j=0;
1494  for (i=0;i<35;i++) {
1495    one_sided_hexomino[j] = hexomino[i];
1496    for (t=0;t<8;t++)
1497      if (one_sided_hexomino[j].transform_list[t]>=4) {
1498        one_sided_hexomino[j].transform_len = t;
1499        j++;
1500        one_sided_hexomino[j] = hexomino[i];
1501        for (u=t;u<8;u++) one_sided_hexomino[j].transform_list[u-t] = one_sided_hexomino[j].transform_list[u];
1502        one_sided_hexomino[j].transform_len -= t;
1503        break;
1504      }
1505    j++;
1506  }
1507}
1508
1509/*
1510Find all the ways of placing all twelve pentominoes
1511into a rectangle whose size is 20x3, 15x4, 12x5 or 10x6.
1512*/
1513
1514static
1515int set_pentomino_puzzle(polyominoesstruct *sp) {
1516  int perm_poly[12], perm_point[5], perm_transform[8], i, p;
1517
1518  switch (NRAND(4)) {
1519    case 0:
1520      sp->width = 20;
1521      sp->height = 3;
1522      break;
1523    case 1:
1524      sp->width = 15;
1525      sp->height = 4;
1526      break;
1527    case 2:
1528      sp->width = 12;
1529      sp->height = 5;
1530      break;
1531    case 3:
1532      sp->width = 10;
1533      sp->height = 6;
1534      break;
1535  }
1536
1537  sp->nr_polyominoes = 12;
1538  set_allocate(sp->polyomino,polyomino_type,12*sizeof(polyomino_type));
1539  random_permutation(12,perm_poly);
1540  for (p=0;p<12;p++) {
1541    copy_polyomino(sp->polyomino[p],pentomino[perm_poly[p]],1);
1542  }
1543
1544  sp->check_ok = check_pentomino_puzzle;
1545
1546  return 1;
1547}
1548
1549/*
1550Many of the following puzzles are inspired by
1551http://www.xs4all.nl/~gp/PolyominoSolver/Polyomino.html
1552*/
1553
1554/*
1555Find all the ways of placing all eighteen one-sided pentominoes
1556into a rectangle.
1557*/
1558
1559static
1560int set_one_sided_pentomino_puzzle(polyominoesstruct *sp) {
1561  int perm_poly[18], perm_point[5], perm_transform[8], i, p;
1562
1563  make_one_sided_pentomino();
1564
1565  switch (NRAND(4)) {
1566    case 0:
1567      sp->width = 30;
1568      sp->height = 3;
1569      break;
1570    case 1:
1571      sp->width = 18;
1572      sp->height = 5;
1573      break;
1574    case 2:
1575      sp->width = 15;
1576      sp->height = 6;
1577      break;
1578    case 3:
1579      sp->width = 10;
1580      sp->height = 9;
1581      break;
1582  }
1583
1584  sp->nr_polyominoes = 18;
1585  set_allocate(sp->polyomino,polyomino_type,18*sizeof(polyomino_type));
1586  random_permutation(18,perm_poly);
1587  for (p=0;p<18;p++) {
1588    copy_polyomino(sp->polyomino[p],one_sided_pentomino[perm_poly[p]],1);
1589  }
1590
1591  sp->check_ok = check_pentomino_puzzle;
1592
1593  return 1;
1594}
1595
1596/*
1597Find all the ways of placing all sixty one-sided hexominoes
1598into a rectangle.
1599*/
1600
1601static
1602int set_one_sided_hexomino_puzzle(polyominoesstruct *sp) {
1603  int perm_poly[60], perm_point[6], perm_transform[8], i, p;
1604
1605  make_one_sided_hexomino();
1606
1607  switch (NRAND(8)) {
1608    case 0:
1609      sp->width = 20;
1610      sp->height = 18;
1611      break;
1612    case 1:
1613      sp->width = 24;
1614      sp->height = 15;
1615      break;
1616    case 2:
1617      sp->width = 30;
1618      sp->height = 12;
1619      break;
1620    case 3:
1621      sp->width = 36;
1622      sp->height = 10;
1623      break;
1624    case 4:
1625      sp->width = 40;
1626      sp->height = 9;
1627      break;
1628    case 5:
1629      sp->width = 45;
1630      sp->height = 8;
1631      break;
1632    case 6:
1633      sp->width = 60;
1634      sp->height = 6;
1635      break;
1636    case 7:
1637      sp->width = 72;
1638      sp->height = 5;
1639      break;
1640  }
1641
1642  sp->nr_polyominoes = 60;
1643  set_allocate(sp->polyomino,polyomino_type,60*sizeof(polyomino_type));
1644  random_permutation(60,perm_poly);
1645  for (p=0;p<60;p++) {
1646    copy_polyomino(sp->polyomino[p],one_sided_hexomino[perm_poly[p]],1);
1647  }
1648
1649  sp->check_ok = check_hexomino_puzzle;
1650
1651  return 1;
1652}
1653
1654/*
1655Find all the ways of placing all five tetrominoes and all twelve
1656pentominoes into a rectangle.
1657*/
1658
1659static
1660int set_tetr_pentomino_puzzle(polyominoesstruct *sp) {
1661  int perm_poly[17], perm_point[5], perm_transform[8], i, p;
1662
1663  switch (NRAND(3)) {
1664    case 0:
1665      sp->width = 20;
1666      sp->height = 4;
1667      break;
1668    case 1:
1669      sp->width = 16;
1670      sp->height = 5;
1671      break;
1672    case 2:
1673      sp->width = 10;
1674      sp->height = 8;
1675      break;
1676  }
1677
1678  sp->nr_polyominoes = 17;
1679  set_allocate(sp->polyomino,polyomino_type,17*sizeof(polyomino_type));
1680  random_permutation(17,perm_poly);
1681  for (p=0;p<5;p++) {
1682    copy_polyomino(sp->polyomino[perm_poly[p]],tetromino[p],1);
1683  }
1684  for (p=0;p<12;p++) {
1685    copy_polyomino(sp->polyomino[perm_poly[p+5]],pentomino[p],1);
1686  }
1687
1688  sp->check_ok = check_tetr_pentomino_puzzle;
1689
1690  return 1;
1691}
1692/*
1693Find all the ways of placing all twelve pentominoes and all thirty five
1694hexominoes into a rectangle whose size is 18x15.
1695*/
1696
1697static
1698int set_pent_hexomino_puzzle(polyominoesstruct *sp) {
1699  int perm_poly[47], perm_point[6], perm_transform[8], i, p;
1700
1701  switch (NRAND(5)) {
1702    case 0:
1703      sp->width = 54;
1704      sp->height = 5;
1705      break;
1706    case 1:
1707      sp->width = 45;
1708      sp->height = 6;
1709      break;
1710    case 2:
1711      sp->width = 30;
1712      sp->height = 9;
1713      break;
1714    case 3:
1715      sp->width = 27;
1716      sp->height = 10;
1717      break;
1718    case 4:
1719      sp->width = 18;
1720      sp->height = 15;
1721      break;
1722  }
1723
1724  sp->nr_polyominoes = 47;
1725  set_allocate(sp->polyomino,polyomino_type,47*sizeof(polyomino_type));
1726  random_permutation(47,perm_poly);
1727  for (p=0;p<12;p++) {
1728    copy_polyomino(sp->polyomino[perm_poly[p]],pentomino[p],1);
1729  }
1730  for (p=0;p<35;p++) {
1731    copy_polyomino(sp->polyomino[perm_poly[p+12]],hexomino[p],1);
1732  }
1733
1734  sp->check_ok = check_pent_hexomino_puzzle;
1735
1736  return 1;
1737}
1738
1739/*
1740Other puzzles:
1741
1742Science News September 20, 1986 Vol 130, No 12
1743Science News November 14, 1987 Vol 132, Pg 310
1744*/
1745
1746/*
1747
1748 *
1749**** fills a 10x5 rectangle
1750
1751*/
1752
1753static struct {int len; point_type point[5];
1754               int transform_len, transform_list[8], max_white;} pentomino1 =
1755  {5, {{0,0}, {1,0}, {2,0}, {3,0}, {1,1}},
1756   8, {0, 1, 2, 3, 4, 5, 6, 7}, 3};
1757
1758static
1759int set_pentomino_puzzle1(polyominoesstruct *sp) {
1760  int perm_point[5], perm_transform[8], i, p;
1761
1762  sp->width = 10;
1763  sp->height =5;
1764
1765  sp->nr_polyominoes = 10;
1766  set_allocate(sp->polyomino,polyomino_type,10*sizeof(polyomino_type));
1767  for (p=0;p<10;p++) {
1768    copy_polyomino(sp->polyomino[p],pentomino1,1);
1769  }
1770
1771  sp->check_ok = check_pentomino_puzzle;
1772
1773  return 1;
1774}
1775
1776/*
1777
1778 *
1779***** fills a 24x23 rectangle
1780
1781*/
1782
1783static struct {int len; point_type point[6];
1784               int transform_len, transform_list[8], max_white;} hexomino1 =
1785  {6, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {1,1}},
1786   8, {0, 1, 2, 3, 4, 5, 6, 7}, 4};
1787
1788static
1789int set_hexomino_puzzle1(polyominoesstruct *sp) {
1790  int perm_point[6], perm_transform[8], i, p;
1791
1792  sp->width = 24;
1793  sp->height =23;
1794
1795  sp->nr_polyominoes = 92;
1796  set_allocate(sp->polyomino,polyomino_type,92*sizeof(polyomino_type));
1797  for (p=0;p<92;p++) {
1798    copy_polyomino(sp->polyomino[p],hexomino1,1);
1799  }
1800
1801  sp->check_ok = check_hexomino_puzzle;
1802
1803  return 1;
1804}
1805
1806/*
1807
1808 **
1809***** fills a 21x26 rectangle
1810
1811(All solutions have 180 degree rotational symmetry)
1812
1813*/
1814
1815static struct {int len; point_type point[7];
1816               int transform_len, transform_list[8], max_white;} heptomino1 =
1817  {7, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {1,1}, {2,1}},
1818   8, {0, 1, 2, 3, 4, 5, 6, 7}, 4};
1819
1820static
1821int set_heptomino_puzzle1(polyominoesstruct *sp) {
1822  int perm_point[7], perm_transform[8], i, p;
1823
1824  sp->rot180 = 1;
1825
1826  sp->width = 26;
1827  sp->height =21;
1828
1829  sp->nr_polyominoes = 78;
1830  set_allocate(sp->polyomino,polyomino_type,78*sizeof(polyomino_type));
1831  for (p=0;p<78;p+=2) {
1832    copy_polyomino(sp->polyomino[p],heptomino1,1);
1833    copy_polyomino(sp->polyomino[p+1],heptomino1,0);
1834  }
1835
1836  sp->check_ok = check_heptomino_puzzle;
1837
1838  return 1;
1839}
1840
1841/* The following puzzles from
1842Polyominoes Puzzles, Patterns, Problems, and Packings Revised (2nd) Edition
1843by Solomon W. Golomb   Princeton University Press 1994
1844*/
1845
1846/*
1847
1848 **
1849***** fills a 28x19 rectangle
1850
1851*/
1852static
1853int set_heptomino_puzzle2(polyominoesstruct *sp) {
1854  int perm_point[7], perm_transform[8], i, p;
1855
1856  sp->width = 28;
1857  sp->height =19;
1858
1859  sp->nr_polyominoes = 76;
1860  set_allocate(sp->polyomino,polyomino_type,76*sizeof(polyomino_type));
1861  for (p=0;p<76;p++) {
1862    copy_polyomino(sp->polyomino[p],heptomino1,1);
1863  }
1864
1865  sp->check_ok = check_heptomino_puzzle;
1866
1867  return 1;
1868}
1869
1870/*
1871
1872***
1873**** fills a 25x22 rectangle
1874****
1875
1876*/
1877
1878static struct {int len; point_type point[11];
1879               int transform_len, transform_list[8], max_white;} elevenomino1 =
1880  {11, {{0,0}, {1,0}, {2,0},
1881        {0,1}, {1,1}, {2,1}, {3,1},
1882        {0,2}, {1,2}, {2,2}, {3,2}},
1883   8, {0, 1, 2, 3, 4, 5, 6, 7}, 6};
1884
1885static
1886int set_elevenomino_puzzle1(polyominoesstruct *sp) {
1887  int perm_point[11], perm_transform[8], i, p;
1888
1889  sp->rot180 = 1;
1890
1891  sp->width = 25;
1892  sp->height =22;
1893
1894  sp->nr_polyominoes = 50;
1895  set_allocate(sp->polyomino,polyomino_type,50*sizeof(polyomino_type));
1896  for (p=0;p<50;p+=2) {
1897    copy_polyomino(sp->polyomino[p],elevenomino1,1);
1898    copy_polyomino(sp->polyomino[p+1],elevenomino1,0);
1899  }
1900
1901  sp->check_ok = check_elevenomino_puzzle;
1902
1903  return 1;
1904}
1905
1906/*
1907
1908 *
1909 *
1910**** fills 32 x 30 rectangle
1911****
1912
1913*/
1914
1915static struct {int len; point_type point[10];
1916               int transform_len, transform_list[8], max_white;} dekomino1 =
1917  {10, {       {1,-1},
1918               {1,0},
1919        {0,1}, {1,1}, {2,1}, {3,1},
1920        {0,2}, {1,2}, {2,2}, {3,2}},
1921   8, {0, 1, 2, 3, 4, 5, 6, 7}, 5};
1922
1923static
1924int set_dekomino_puzzle1(polyominoesstruct *sp) {
1925  int perm_point[10], perm_transform[8], i, p;
1926
1927  sp->width = 32;
1928  sp->height =30;
1929
1930  sp->nr_polyominoes = 96;
1931  set_allocate(sp->polyomino,polyomino_type,96*sizeof(polyomino_type));
1932  for (p=0;p<96;p++) {
1933    copy_polyomino(sp->polyomino[p],dekomino1,1);
1934  }
1935
1936  sp->check_ok = check_dekomino_puzzle;
1937
1938  return 1;
1939}
1940
1941/*
1942
1943 *
1944***  fills 96 x 26 rectangle
1945****
1946
1947*/
1948
1949static struct {int len; point_type point[10];
1950               int transform_len, transform_list[8], max_white;} octomino1 =
1951  {8, {        {1,0},
1952        {0,1}, {1,1}, {2,1},
1953        {0,2}, {1,2}, {2,2}, {3,2}},
1954   8, {0, 1, 2, 3, 4, 5, 6, 7}, 5};
1955
1956static
1957int set_octomino_puzzle1(polyominoesstruct *sp) {
1958  int perm_point[8], perm_transform[8], i, p;
1959
1960  sp->width = 96;
1961  sp->height =26;
1962
1963  sp->nr_polyominoes = 312;
1964  set_allocate(sp->polyomino,polyomino_type,312*sizeof(polyomino_type));
1965  for (p=0;p<312;p++) {
1966    copy_polyomino(sp->polyomino[p],octomino1,1);
1967  }
1968
1969  sp->check_ok = check_octomino_puzzle;
1970
1971  return 1;
1972}
1973
1974/*
1975
1976 *   fills 15 x 15 rectangle
1977****
1978
1979*/
1980
1981static
1982int set_pentomino_puzzle2(polyominoesstruct *sp) {
1983  int perm_point[5], perm_transform[8], i, p;
1984
1985  sp->width = 15;
1986  sp->height =15;
1987
1988  sp->nr_polyominoes = 45;
1989  set_allocate(sp->polyomino,polyomino_type,45*sizeof(polyomino_type));
1990  for (p=0;p<45;p++) {
1991    copy_polyomino(sp->polyomino[p],pentomino1,1);
1992  }
1993
1994  sp->check_ok = check_pentomino_puzzle;
1995
1996  return 1;
1997}
1998
1999/*
2000
2001***
2002**** fills a 47x33 rectangle
2003****
2004
2005*/
2006
2007static
2008int set_elevenomino_puzzle2(polyominoesstruct *sp) {
2009  int perm_point[11], perm_transform[8], i, p;
2010
2011  sp->width = 47;
2012  sp->height =33;
2013
2014  sp->nr_polyominoes = 141;
2015  set_allocate(sp->polyomino,polyomino_type,141*sizeof(polyomino_type));
2016  for (p=0;p<141;p++) {
2017    copy_polyomino(sp->polyomino[p],elevenomino1,1);
2018  }
2019
2020  sp->check_ok = check_elevenomino_puzzle;
2021
2022  return 1;
2023}
2024
2025/**************************************************
2026The main functions.
2027**************************************************/
2028
2029#define allocate(p,type,size) p = (type *) malloc(size); if ((p)==NULL) {free_polyominoes(sp); return;}
2030
2031void
2032init_polyominoes(ModeInfo * mi) {
2033  polyominoesstruct *sp;
2034  int i,x,y, start;
2035  int box1, box2;
2036  int *perm;
2037
2038  if (polyominoeses == NULL) {
2039    if ((polyominoeses
2040         = (polyominoesstruct *) calloc(MI_NUM_SCREENS(mi),sizeof (polyominoesstruct)))
2041        == NULL)
2042      return;
2043  }
2044  sp = &polyominoeses[MI_SCREEN(mi)];
2045
2046  free_polyominoes(sp);
2047
2048  sp->rot180 = 0;
2049  sp->counter = 0;
2050
2051  if (MI_IS_FULLRANDOM(mi)) {
2052    sp->identical = (Bool) (LRAND() & 1);
2053    sp->use3D = (Bool) (NRAND(4));
2054  } else {
2055    sp->identical = identical;
2056    sp->use3D = !plain;
2057  }
2058  if (sp->identical) {
2059    switch (NRAND(9)) {
2060      case 0:
2061        if (!set_pentomino_puzzle1(sp))
2062          return;
2063        break;
2064      case 1:
2065        if (!set_hexomino_puzzle1(sp))
2066          return;
2067        break;
2068      case 2:
2069        if (!set_heptomino_puzzle1(sp))
2070          return;
2071        break;
2072      case 3:
2073        if (!set_heptomino_puzzle2(sp))
2074          return;
2075        break;
2076      case 4:
2077        if (!set_elevenomino_puzzle1(sp))
2078          return;
2079        break;
2080      case 5:
2081        if (!set_dekomino_puzzle1(sp))
2082          return;
2083        break;
2084      case 6:
2085        if (!set_octomino_puzzle1(sp))
2086          return;
2087        break;
2088      case 7:
2089        if (!set_pentomino_puzzle2(sp))
2090          return;
2091        break;
2092      case 8:
2093        if (!set_elevenomino_puzzle2(sp))
2094          return;
2095        break;
2096    }
2097  } else {
2098    switch (NRAND(5)) {
2099      case 0:
2100        if (!set_pentomino_puzzle(sp))
2101          return;
2102        break;
2103      case 1:
2104        if (!set_one_sided_pentomino_puzzle(sp))
2105          return;
2106        break;
2107      case 2:
2108        if (!set_one_sided_hexomino_puzzle(sp))
2109          return;
2110        break;
2111      case 3:
2112        if (!set_pent_hexomino_puzzle(sp))
2113          return;
2114        break;
2115      case 4:
2116        if (!set_tetr_pentomino_puzzle(sp))
2117          return;
2118        break;
2119    }
2120  }
2121
2122  allocate(sp->attach_list,int,sp->nr_polyominoes*sizeof(int));
2123  sp->nr_attached = 0;
2124
2125  if (sp->identical) {
2126    allocate(sp->reason_to_not_attach,int,sp->nr_polyominoes*sp->nr_polyominoes*sizeof(int));
2127  }
2128
2129  allocate(sp->array,int,sp->width*sp->height*sizeof(int));
2130  allocate(sp->changed_array,int,sp->width*sp->height*sizeof(int));
2131  for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) ARRAY(x,y) = -1;
2132
2133  sp->left_right = NRAND(2);
2134  sp->top_bottom = NRAND(2);
2135
2136  box1 = MI_WIDTH(mi)/(sp->width+2);
2137  box2 = MI_HEIGHT(mi)/(sp->height+2);
2138  if (box1<box2)
2139    sp->box = box1;
2140  else
2141    sp->box = box2;
2142
2143  if (sp->box >= 12) {
2144    sp->box = (sp->box/12)*12;
2145    create_bitmaps(mi,sp);
2146    if (!sp->use_bitmaps)
2147      free_bitmaps(sp);
2148   }
2149   else
2150     sp->use_bitmaps = 0;
2151
2152  if (!sp->use_bitmaps) {
2153    allocate(sp->rectangles,XRectangle,sp->width*sp->height*sizeof(XRectangle));
2154    allocate(sp->lines,XSegment,sp->width*sp->height*sizeof(XSegment));
2155  }
2156
2157  allocate(perm,int,sp->nr_polyominoes*sizeof(int));
2158  random_permutation(sp->nr_polyominoes, perm);
2159  sp->mono = MI_NPIXELS(mi) < 12;
2160  start = NRAND(MI_NPIXELS(mi));
2161  for (i=0;i<sp->nr_polyominoes;i++)
2162    if (!sp->mono) {
2163      sp->polyomino[i].color = MI_PIXEL(mi,(perm[i]*MI_NPIXELS(mi) / sp->nr_polyominoes + start) % MI_NPIXELS(mi));
2164      if (sp->rot180) {
2165         sp->polyomino[i+1].color = sp->polyomino[i].color;
2166         i++;
2167      }
2168    }
2169    else
2170      if(sp->use_bitmaps)
2171        sp->polyomino[i].color = MI_WHITE_PIXEL(mi);
2172      else
2173        sp->polyomino[i].color = MI_BLACK_PIXEL(mi);
2174  free(perm);
2175
2176  if (sp->use_bitmaps) {
2177    if (sp->mono)
2178      sp->border_color = MI_WHITE_PIXEL(mi);
2179    else
2180      sp->border_color = MI_PIXEL(mi,NRAND(MI_NPIXELS(mi)));
2181  }
2182
2183  sp->x_margin = (MI_WIDTH(mi)-sp->box*sp->width)/2;
2184  sp->y_margin = (MI_HEIGHT(mi)-sp->box*sp->height)/2;
2185
2186  sp->wait = 0;
2187
2188  /* Clear the background. */
2189  MI_CLEARWINDOW(mi);
2190 
2191}
2192
2193void
2194draw_polyominoes(ModeInfo * mi) {
2195  polyominoesstruct *sp;
2196  int poly_no,point_no,transform_index,done,another_attachment_try;
2197  point_type attach_point;
2198  int i,detach_until;
2199
2200  if (polyominoeses == NULL)
2201    return;
2202  sp = &polyominoeses[MI_SCREEN(mi)];
2203
2204  if (MI_CYCLES(mi) != 0) {
2205    if (++sp->counter > MI_CYCLES(mi)) {
2206#ifdef STANDALONE
2207      erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
2208#endif /* STANDALONE */
2209      init_polyominoes(mi);
2210      return;
2211    }
2212  }
2213
2214  if (sp->box == 0) {
2215#ifdef STANDALONE
2216    erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
2217#endif /* STANDALONE */
2218    init_polyominoes(mi);
2219    return;
2220  }
2221
2222  MI_IS_DRAWN(mi) = True;
2223  sp->wait--;
2224  if (sp->wait>0) return;
2225
2226  memset(sp->changed_array,0,sp->width*sp->height*sizeof(int));
2227
2228  poly_no = first_poly_no(sp);
2229  point_no = 0;
2230  transform_index = 0;
2231  done = 0;
2232  another_attachment_try = 1;
2233  find_blank(sp,&attach_point);
2234  if (sp->identical && sp->nr_attached < sp->nr_polyominoes)
2235    memset(&REASON_TO_NOT_ATTACH(sp->nr_attached,0),0,sp->nr_polyominoes*sizeof(int));
2236  while(!done) {
2237    if (sp->nr_attached < sp->nr_polyominoes) {
2238      while (!done && another_attachment_try) {
2239        done = attach(sp,poly_no,point_no,transform_index,attach_point,0,&REASON_TO_NOT_ATTACH(sp->nr_attached,0));
2240        if (done && sp->rot180) {
2241          poly_no = first_poly_no(sp);
2242          done = attach(sp,poly_no,point_no,transform_index,attach_point,1,&REASON_TO_NOT_ATTACH(sp->nr_attached-1,0));
2243          if (!done)
2244            detach(sp,&poly_no,&point_no,&transform_index,&attach_point,0);
2245        }
2246        if (!done)
2247          another_attachment_try = next_attach_try(sp,&poly_no,&point_no,&transform_index);
2248      }
2249    }
2250
2251    if (sp->identical) {
2252      if (!done) {
2253        if (sp->nr_attached == 0)
2254          done = 1;
2255        else {
2256          detach_until=sp->nr_attached-1;
2257          if (sp->nr_attached < sp->nr_polyominoes)
2258            while (detach_until>0 && REASON_TO_NOT_ATTACH(sp->nr_attached,detach_until)==0)
2259              detach_until--;
2260          while (sp->nr_attached>detach_until) {
2261            if (sp->rot180)
2262              detach(sp,&poly_no,&point_no,&transform_index,&attach_point,1);
2263            detach(sp,&poly_no,&point_no,&transform_index,&attach_point,0);
2264            if (sp->nr_attached+1+sp->rot180 < sp->nr_polyominoes)
2265              for (i=0;i<sp->nr_polyominoes;i++)
2266                REASON_TO_NOT_ATTACH(sp->nr_attached,i) |= REASON_TO_NOT_ATTACH(sp->nr_attached+1+sp->rot180,i);
2267          }
2268          another_attachment_try = next_attach_try(sp,&poly_no,&point_no,&transform_index);
2269        }
2270      }
2271    }
2272    else {
2273      if (!done) {
2274        if (sp->nr_attached == 0)
2275          done = 1;
2276        else {
2277          if (sp->rot180)
2278            detach(sp,&poly_no,&point_no,&transform_index,&attach_point,1);
2279          detach(sp,&poly_no,&point_no,&transform_index,&attach_point,0);
2280        }
2281        another_attachment_try = next_attach_try(sp,&poly_no,&point_no,&transform_index);
2282      }
2283    }
2284  }
2285
2286  if (sp->use_bitmaps)
2287    draw_with_bitmaps(mi,sp);
2288  else
2289    draw_without_bitmaps(mi,sp);
2290
2291  if (sp->nr_attached == sp->nr_polyominoes)
2292    sp->wait = 100;
2293  else
2294    sp->wait = 0;
2295}
2296
2297void
2298release_polyominoes(ModeInfo * mi) {
2299  int screen;
2300 
2301  if (polyominoeses != NULL) {
2302    for (screen=0;screen<MI_NUM_SCREENS(mi); screen++)
2303      free_polyominoes(&polyominoeses[screen]);
2304    (void) free((void *) polyominoeses);
2305    polyominoeses = (polyominoesstruct *) NULL;
2306  }
2307}
2308
2309void
2310refresh_polyominoes(ModeInfo * mi) {
2311  MI_CLEARWINDOW(mi);
2312}
2313
2314#endif /* MODE_polyominoes */
Note: See TracBrowser for help on using the repository browser.