summaryrefslogtreecommitdiffstats
path: root/hacks/polyominoes.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/polyominoes.c')
-rw-r--r--hacks/polyominoes.c2368
1 files changed, 2368 insertions, 0 deletions
diff --git a/hacks/polyominoes.c b/hacks/polyominoes.c
new file mode 100644
index 0000000..b87c3d3
--- /dev/null
+++ b/hacks/polyominoes.c
@@ -0,0 +1,2368 @@
+/* -*- Mode: C; tab-width: 4 -*- */
+/* polyominoes --- Shows attempts to place polyominoes into a rectangle */
+
+#if 0
+static const char sccsid[] = "@(#)polyominoes.c 5.01 2000/12/18 xlockmore";
+#endif
+
+/*
+ * Copyright (c) 2000 by Stephen Montgomery-Smith <stephen@math.missouri.edu>
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * This file is provided AS IS with no warranties of any kind. The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof. In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
+ *
+ * Revision History:
+ * 07-Jan-2001: Made improvement to the search algorithm for the puzzles
+ * involving identical polyominoes (via the variable
+ * reason_to_not_attach). By Stephen Montgomery-Smith.
+ * 20-Dec-2000: Added more puzzles at David Bagley's request.
+ * 27-Nov-2000: Adapted from euler2d.c Copyright (c) 2000 by Stephen
+ * Montgomery-Smith
+ * 05-Jun-2000: Adapted from flow.c Copyright (c) 1996 by Tim Auckland
+ * 18-Jul-1996: Adapted from swarm.c Copyright (c) 1991 by Patrick J. Naughton.
+ * 31-Aug-1990: Adapted from xswarm by Jeff Butterworth. (butterwo@ncsc.org)
+ */
+
+#ifdef STANDALONE
+# define MODE_polyominoes
+#define DEFAULTS "*delay: 10000 \n" \
+ "*cycles: 2000 \n" \
+ "*ncolors: 64 \n" \
+ "*fpsSolid: true \n" \
+
+# define release_polyominoes 0
+# define reshape_polyominoes 0
+# define polyominoes_handle_event 0
+# define SMOOTH_COLORS
+# include "xlockmore.h" /* in xscreensaver distribution */
+#else /* STANDALONE */
+# include "xlock.h" /* in xlockmore distribution */
+#endif /* STANDALONE */
+
+#ifdef MODE_polyominoes
+#define DEF_IDENTICAL "False"
+#define DEF_PLAIN "False"
+
+static Bool identical;
+static Bool plain;
+
+#undef countof
+#define countof(x) (sizeof((x))/sizeof((*x)))
+
+static XrmOptionDescRec opts[] =
+{
+ {"-identical", ".polyominoes.identical", XrmoptionNoArg, "on"},
+ {"+identical", ".polyominoes.identical", XrmoptionNoArg, "off"},
+ {"-plain", ".polyominoes.plain", XrmoptionNoArg, "on"},
+ {"+plain", ".polyominoes.plain", XrmoptionNoArg, "off"}
+};
+static argtype vars[] =
+{
+ {&identical, "identical", "Identical", DEF_IDENTICAL, t_Bool},
+ {&plain, "plain", "Plain", DEF_PLAIN, t_Bool}
+};
+static OptionStruct desc[] =
+{
+ {"-/+identical", "turn on/off puzzles where the polyomino pieces are identical"},
+ {"-/+plain", "turn on/off plain pieces"}
+};
+
+ENTRYPOINT ModeSpecOpt polyominoes_opts =
+{sizeof opts / sizeof opts[0], opts,
+ sizeof vars / sizeof vars[0], vars, desc};
+
+#ifdef USE_MODULES
+ModStruct polyominoes_description = {
+ "polyominoes", "init_polyominoes", "draw_polyominoes", (char *) NULL,
+ "refresh_polyominoes", "init_polyominoes", "free_polyominoes",
+ &polyominoes_opts, 6000, 1, 8192, 1, 64, 1.0, "",
+ "Shows attempts to place polyominoes into a rectangle", 0, NULL
+};
+
+#endif
+
+/* Each polyomino is described by several quantities:
+ len: the number of squares in the polyomino;
+ point: the list of points;
+ tranform_len: the number of items in transform_list;
+ transform_list: a list of transformations that need to be done in order
+ to get all rotations and reflections (see the function
+ transform below);
+ max_white: the maximum number of white squares covered if polyomino
+ is placed on a chess board;
+ color: it's display color;
+ attached: whether it is currently attached to the rectangle;
+ attach_point: point on rectangle where attached;
+ point_no: the number of the point where it is attached;
+ transform_index: which element of transform_list is currently being used.
+*/
+
+typedef struct {int x,y;} point_type;
+
+typedef struct {int len; point_type *point;
+ int transform_len, transform_list[8], max_white;
+ unsigned long color;
+ int attached;
+ point_type attach_point;
+ int point_no, transform_index;} polyomino_type;
+
+
+typedef struct _polyominoesstruct{
+ int wait;
+
+ int width, height;
+ unsigned border_color;
+ int mono;
+
+ polyomino_type *polyomino;
+ int nr_polyominoes;
+ Bool identical, use3D;
+ int *attach_list;
+ int nr_attached;
+
+/* The array that tells where the polyominoes are attached. */
+ int *array, *changed_array;
+
+/* These specify the dimensions of how things appear on the screen. */
+ int box, x_margin, y_margin;
+
+/* These booleans decide in which way to try to attach the polyominoes. */
+ int left_right, top_bottom;
+
+/* Bitmaps for display purposes. */
+ int use_bitmaps;
+ XImage *bitmaps[256];
+
+/* Structures used for display purposes if there is not enough memory
+ to allocate bitmaps (or if the screen is small). */
+ XSegment *lines;
+ XRectangle *rectangles;
+
+/* A procedure that may be used to see if certain configurations
+ are permissible. */
+ int (*check_ok)(struct _polyominoesstruct *sp);
+
+/* Tells program that solutions are invariant under 180 degree
+ rotation. */
+ int rot180;
+
+/* This is a variable used in the case that all the polyominoes are identical
+ that will further prune the search tree. Essentially it will be
+ int reason_to_not_attach[nr_polynominoes][nr_polynominoes];
+ Let me first explain the effect it is trying to overcome. Often
+ in the search process, the computer will first try to fit shapes into
+ a region (call it A), and then into another region (call it B) that is
+ essentially disjoint from A. But it may be that it just is not possible
+ to fit shapes into region B. So it fits something into A, and then
+ tries to fit something into B. Failing it fits something else into A,
+ and then tried again to fit something into B. Thus the program is trying
+ again and again to fit something into B, when it should have figured out
+ the first time that it was impossible.
+
+ To overcome this, everytime we try to attach a piece, we collect the reasons
+ why it cannot be attached (a boolean for each piece that got in the way).
+ If we see that a piece cannot be attached, we detach the other pieces until
+ we have detached at least one piece for which the boolean reason_to_not_attach
+ is set.
+*/
+ int *reason_to_not_attach;
+
+ int counter;
+} polyominoesstruct;
+
+#define ARRAY(x,y) (sp->array[(x)*sp->height+(y)])
+#define CHANGED_ARRAY(x,y) (sp->changed_array[(x)*sp->height+(y)])
+#define ARRAY_P(p) (sp->array[(p).x*sp->height+(p).y])
+#define CHANGED_ARRAY_P(p) (sp->changed_array[(p).x*sp->height+(p).y])
+#define ARR(x,y) (((x)<0||(x)>=sp->width||(y)<0||(y)>=sp->height)?-2:ARRAY(x,y))
+
+#define REASON_TO_NOT_ATTACH(x,y) (sp->reason_to_not_attach[(x)*sp->nr_polyominoes+(y)])
+
+#define ROUND8(n) ((((n)+7)/8)*8)
+
+/* Defines to index the bitmaps. A set bit indicates that an edge or
+ corner is required. */
+#define LEFT (1<<0)
+#define RIGHT (1<<1)
+#define UP (1<<2)
+#define DOWN (1<<3)
+#define LEFT_UP (1<<4)
+#define LEFT_DOWN (1<<5)
+#define RIGHT_UP (1<<6)
+#define RIGHT_DOWN (1<<7)
+#define IS_LEFT(n) ((n) & LEFT)
+#define IS_RIGHT(n) ((n) & RIGHT)
+#define IS_UP(n) ((n) & UP)
+#define IS_DOWN(n) ((n) & DOWN)
+#define IS_LEFT_UP(n) ((n) & LEFT_UP)
+#define IS_LEFT_DOWN(n) ((n) & LEFT_DOWN)
+#define IS_RIGHT_UP(n) ((n) & RIGHT_UP)
+#define IS_RIGHT_DOWN(n) ((n) & RIGHT_DOWN)
+
+/* Defines to access the bitmaps. */
+#define BITNO(x,y) ((x)+(y)*ROUND8(sp->box))
+#define SETBIT(n,x,y) {data[BITNO(x,y)/8] |= 1<<(BITNO(x,y)%8);}
+#define RESBIT(n,x,y) {data[BITNO(x,y)/8] &= ~(1<<(BITNO(x,y)%8));}
+#define TWOTHIRDSBIT(n,x,y) {if ((x+y-1)%3) SETBIT(n,x,y) else RESBIT(n,x,y)}
+#define HALFBIT(n,x,y) {if ((x-y)%2) SETBIT(n,x,y) else RESBIT(n,x,y)}
+#define THIRDBIT(n,x,y) {if (!((x-y-1)%3)) SETBIT(n,x,y) else RESBIT(n,x,y)}
+#define THREEQUARTERSBIT(n,x,y) \
+ {if ((y%2)||((x+2+y/2+1)%2)) SETBIT(n,x,y) else RESBIT(n,x,y)}
+#define NOTHALFBIT(n,x,y) {if ((x-y)%2) RESBIT(n,x,y) else SETBIT(n,x,y)}
+
+/* Parameters for bitmaps. */
+#define G ((sp->box/45)+1) /* 1/2 of gap between polyominoes. */
+#define T ((sp->box<=12)?1:(G*2)) /* Thickness of walls of polyominoes. */
+#define R ((sp->box<=12)?1:(G*6)) /* Amount of rounding. */
+#define RT ((sp->box<=12)?1:(G*3)) /* Thickness of wall of rounded parts.
+ Here 3 is an approximation to 2 sqrt(2). */
+#define RR 0 /* Roof ridge thickness */
+
+#if 0
+/* A list of those bitmaps we need to create to display any pentomino. */
+/* (not used right now because it does not seem to work for hexonimoes.) */
+
+static int bitmaps_needed[] =
+{
+ LEFT_UP|LEFT_DOWN|RIGHT_UP|RIGHT_DOWN,
+
+ LEFT|RIGHT_UP|RIGHT_DOWN,
+ RIGHT|LEFT_UP|LEFT_DOWN,
+ UP|LEFT_DOWN|RIGHT_DOWN,
+ DOWN|LEFT_UP|RIGHT_UP,
+ LEFT|RIGHT_UP,
+ RIGHT|LEFT_UP,
+ UP|LEFT_DOWN,
+ DOWN|LEFT_UP,
+ LEFT|RIGHT_DOWN,
+ RIGHT|LEFT_DOWN,
+ UP|RIGHT_DOWN,
+ DOWN|RIGHT_UP,
+
+/* These needed for hexonimoes*/
+ LEFT,
+ RIGHT,
+ UP,
+ DOWN,
+ LEFT_DOWN|RIGHT_UP|RIGHT_DOWN,
+ LEFT_UP|RIGHT_UP|RIGHT_DOWN,
+ LEFT_UP|LEFT_DOWN|RIGHT_DOWN,
+ LEFT_UP|LEFT_DOWN|RIGHT_UP,
+
+ LEFT|UP|RIGHT_DOWN,
+ LEFT|DOWN|RIGHT_UP,
+ RIGHT|UP|LEFT_DOWN,
+ RIGHT|DOWN|LEFT_UP,
+ LEFT|UP,
+ LEFT|DOWN,
+ RIGHT|UP,
+ RIGHT|DOWN,
+
+ LEFT|RIGHT,
+ UP|DOWN,
+
+ RIGHT|UP|DOWN,
+ LEFT|UP|DOWN,
+ LEFT|RIGHT|DOWN,
+ LEFT|RIGHT|UP,
+
+ -1
+};
+
+static int bitmap_needed(int n)
+{
+ int i;
+
+ for (i=0;bitmaps_needed[i]!=-1;i++)
+ if (n == bitmaps_needed[i])
+ return 1;
+ return 0;
+}
+
+#endif
+
+/* Some debugging routines.
+
+static void print_board(polyominoesstruct *sp)
+{
+ int x,y;
+ for (y=0;y<sp->height;y++) {
+ for (x=0;x<sp->width;x++)
+ if (ARRAY(x,y) == -1)
+ fprintf(stderr," ");
+ else
+ fprintf(stderr,"%c",'a'+ARRAY(x,y));
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"\n");
+}
+
+static void print_points(point_type *point, int len)
+{
+ int i;
+
+ for (i=0;i<len;i++)
+ fprintf(stderr,"(%d %d) ",point[i].x,point[i].y);
+}
+
+static void print_polyomino(polyomino_type poly)
+{
+ int i;
+
+ print_points(poly.point,poly.len);
+ fprintf(stderr,"\n");
+ for (i=0;i<poly.transform_len;i++)
+ fprintf(stderr,"%d ",poly.transform_list[i]);
+ fprintf(stderr,"\n");
+}
+*/
+
+static polyominoesstruct *polyominoeses = (polyominoesstruct *) NULL;
+
+static
+void random_permutation(int n, int a[])
+{
+ int i,j,k,r;
+
+ for (i=0;i<n;i++) a[i] = -1;
+ for (i=0;i<n;i++) {
+ r=NRAND(n-i);
+ k=0;
+ while(a[k]!=-1) k++;
+ for (j=0;j<r;j++) {
+ k++;
+ while(a[k]!=-1) k++;
+ }
+ a[k]=i;
+ }
+}
+
+
+/************************************************************
+These are the routines for manipulating the polyominoes and
+attaching and detaching them from the rectangle.
+************************************************************/
+
+static void transform(point_type in, point_type offset, int transform_no,
+ point_type attach_point, point_type *out) {
+ switch (transform_no) {
+ case 0: out->x=in.x-offset.x+attach_point.x;
+ out->y=in.y-offset.y+attach_point.y;
+ break;
+ case 1: out->x=-(in.y-offset.y)+attach_point.x;
+ out->y=in.x-offset.x+attach_point.y;
+ break;
+ case 2: out->x=-(in.x-offset.x)+attach_point.x;
+ out->y=-(in.y-offset.y)+attach_point.y;
+ break;
+ case 3: out->x=in.y-offset.y+attach_point.x;
+ out->y=-(in.x-offset.x)+attach_point.y;
+ break;
+ case 4: out->x=-(in.x-offset.x)+attach_point.x;
+ out->y=in.y-offset.y+attach_point.y;
+ break;
+ case 5: out->x=in.y-offset.y+attach_point.x;
+ out->y=in.x-offset.x+attach_point.y;
+ break;
+ case 6: out->x=in.x-offset.x+attach_point.x;
+ out->y=-(in.y-offset.y)+attach_point.y;
+ break;
+ case 7: out->x=-(in.y-offset.y)+attach_point.x;
+ out->y=-(in.x-offset.x)+attach_point.y;
+ break;
+ }
+}
+
+static int first_poly_no(polyominoesstruct *sp)
+{
+ int poly_no;
+
+ poly_no = 0;
+ while(poly_no<sp->nr_polyominoes && sp->polyomino[poly_no].attached)
+ poly_no++;
+ return poly_no;
+}
+
+static void next_poly_no(polyominoesstruct *sp, int *poly_no)
+{
+
+ if (sp->identical) {
+ *poly_no = sp->nr_polyominoes;
+ } else {
+ do {
+ (*poly_no)++;
+ } while (*poly_no<sp->nr_polyominoes && sp->polyomino[*poly_no].attached);
+ }
+}
+
+/* check_all_regions_multiple_of looks for connected regions of
+ blank spaces, and returns 0 if it finds a connected region containing
+ a number of blanks that is not a multiple of n.
+*/
+
+static void count_adjacent_blanks(polyominoesstruct *sp, int *count, int x, int y, int blank_mark)
+{
+
+ if (ARRAY(x,y) == -1) {
+ (*count)++;
+ ARRAY(x,y) = blank_mark;
+ if (x>=1) count_adjacent_blanks(sp, count,x-1,y,blank_mark);
+ if (x<sp->width-1) count_adjacent_blanks(sp, count,x+1,y,blank_mark);
+ if (y>=1) count_adjacent_blanks(sp, count,x,y-1,blank_mark);
+ if (y<sp->height-1) count_adjacent_blanks(sp, count,x,y+1,blank_mark);
+ }
+}
+
+static int check_all_regions_multiple_of(polyominoesstruct *sp, int n)
+{
+ int x,y,count,good = 1;
+
+ for (x=0;x<sp->width && good;x++) for (y=0;y<sp->height && good;y++) {
+ count = 0;
+ count_adjacent_blanks(sp, &count,x,y,-2);
+ good = count%n == 0;
+ }
+
+ for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++)
+ if (ARRAY(x,y) == -2)
+ ARRAY(x,y) = -1;
+
+ return good;
+}
+
+static int check_all_regions_positive_combination_of(polyominoesstruct *sp, int m, int n)
+{
+ int x,y,count,good = 1;
+
+ for (x=0;x<sp->width && good;x++) for (y=0;y<sp->height && good;y++) {
+ count = 0;
+ count_adjacent_blanks(sp, &count,x,y,-2);
+ good = 0;
+ for (;count>=0 && !good;count-=m)
+ good = count%n == 0;
+ }
+
+ for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++)
+ if (ARRAY(x,y) == -2)
+ ARRAY(x,y) = -1;
+
+ return good;
+}
+
+static int find_smallest_blank_component(polyominoesstruct *sp)
+{
+ int x,y,size,smallest_size,blank_mark,smallest_mark;
+
+ smallest_mark = blank_mark = -10;
+ smallest_size = 1000000000;
+ for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) if (ARRAY(x,y) == -1) {
+ size = 0;
+ count_adjacent_blanks(sp, &size,x,y,blank_mark);
+ if (size<smallest_size) {
+ smallest_mark = blank_mark;
+ smallest_size = size;
+ }
+ blank_mark--;
+ }
+
+ return smallest_mark;
+}
+
+/* "Chess board" check - see init_max_whites_list above for more details.
+*/
+/* If the rectangle is alternatively covered by white and black
+ squares (chess board style), then this gives the list of
+ the maximal possible whites covered by each polyomino. It
+ is used by the function whites_ok which makes sure that the
+ array has a valid number of white or black remaining blanks left.
+*/
+
+static int whites_ok(polyominoesstruct *sp)
+{
+ int x,y,poly_no,whites=0,blacks=0,max_white=0,min_white=0;
+
+ for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) {
+ if (ARRAY(x,y) == -1 && (x+y)%2) whites++;
+ if (ARRAY(x,y) == -1 && (x+y+1)%2) blacks++;
+ }
+ for (poly_no=0;poly_no<sp->nr_polyominoes;poly_no++) if (!sp->polyomino[poly_no].attached) {
+ max_white += sp->polyomino[poly_no].max_white;
+ min_white += sp->polyomino[poly_no].len - sp->polyomino[poly_no].max_white;
+ }
+ return (min_white <= blacks && min_white <= whites
+ && blacks <= max_white && whites <= max_white);
+}
+
+/* This routine looks at the point (x,y) and sees how many polyominoes
+ and all their various transforms may be attached there.
+*/
+
+static int
+score_point(polyominoesstruct *sp, int x, int y, int min_score_so_far)
+{
+ int poly_no, point_no, transform_index, i, attachable;
+ point_type attach_point = { 0, 0 }, target_point = { 0, 0 };
+ int score = 0;
+
+ if (x>=1 && x<sp->width-1 && y>=1 && y<sp->height-1 &&
+ ARRAY(x-1,y-1)<0 && ARRAY(x-1,y)<0 && ARRAY(x-1,y+1)<0 &&
+ ARRAY(x+1,y-1)<0 && ARRAY(x+1,y)<0 && ARRAY(x+1,y+1)<0 &&
+ ARRAY(x,y-1)<0 && ARRAY(x,y+1)<0)
+ return 10000;
+
+ attach_point.x = x;
+ attach_point.y = y;
+ for (poly_no=first_poly_no(sp);poly_no<sp->nr_polyominoes;next_poly_no(sp,&poly_no))
+ if (!sp->polyomino[poly_no].attached) {
+ for (point_no=0;point_no<sp->polyomino[poly_no].len;point_no++)
+ for (transform_index=0;transform_index<sp->polyomino[poly_no].transform_len;transform_index++) {
+ attachable = 1;
+ for (i=0;i<sp->polyomino[poly_no].len;i++) {
+ transform(sp->polyomino[poly_no].point[i],
+ sp->polyomino[poly_no].point[point_no],
+ sp->polyomino[poly_no].transform_list[transform_index],
+ attach_point, &target_point);
+ if ( ! ((target_point.x>=0) && (target_point.x<sp->width)
+ && (target_point.y>=0) && (target_point.y<sp->height)
+ && (ARRAY_P(target_point)<0))) {
+ attachable = 0;
+ break;
+ }
+ }
+ if (attachable) {
+ score++;
+ if (score>=min_score_so_far)
+ return score;
+ }
+ }
+ }
+
+ return score;
+}
+
+static void find_blank(polyominoesstruct *sp, point_type *point)
+{
+ int score, worst_score;
+ int x, y;
+ int blank_mark;
+
+ blank_mark = find_smallest_blank_component(sp);
+
+ worst_score = 1000000;
+ for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) if (ARRAY(x,y)==blank_mark) {
+ score = 100*score_point(sp,x,y,worst_score);
+ if (score>0) {
+ if (sp->left_right) score += 10*x;
+ else score += 10*(sp->width-1-x);
+ if (sp->top_bottom) score += y;
+ else score += (sp->height-1-y);
+ }
+ if (score<worst_score) {
+ point->x = x;
+ point->y = y;
+ worst_score = score;
+ }
+ }
+
+ for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++)
+ if (ARRAY(x,y)<0) ARRAY(x,y) = -1;
+}
+
+/* Detaches the most recently attached polyomino. */
+
+static
+void detach(polyominoesstruct *sp, int *poly_no, int *point_no, int *transform_index, point_type *attach_point, int rot180)
+{
+ int i;
+ point_type target_point = { 0, 0 };
+
+ if (sp->nr_attached == 0) return;
+ sp->nr_attached--;
+ *poly_no = sp->attach_list[sp->nr_attached];
+ *point_no = sp->polyomino[*poly_no].point_no;
+ *transform_index = sp->polyomino[*poly_no].transform_index;
+ *attach_point = sp->polyomino[*poly_no].attach_point;
+ for (i=0;i<sp->polyomino[*poly_no].len;i++) {
+ transform(sp->polyomino[*poly_no].point[i],
+ sp->polyomino[*poly_no].point[*point_no],
+ sp->polyomino[*poly_no].transform_list[*transform_index]^(rot180<<1),
+ *attach_point, &target_point);
+ ARRAY_P(target_point) = -1;
+ CHANGED_ARRAY_P(target_point) = 1;
+ }
+
+ sp->polyomino[*poly_no].attached = 0;
+}
+
+/* Attempts to attach a polyomino at point (x,y) at the
+ point_no-th point of that polyomino, using the transform
+ transform_no. Returns 1 if successful.
+*/
+
+static
+int attach(polyominoesstruct *sp, int poly_no, int point_no, int transform_index, point_type attach_point, int rot180,
+ int *reason_to_not_attach) {
+ point_type target_point = { 0, 0 };
+ int i;
+ int attachable = 1, worst_reason_not_to_attach = 1000000000;
+
+ if (rot180) {
+ attach_point.x = sp->width-1-attach_point.x;
+ attach_point.y = sp->height-1-attach_point.y;
+ }
+
+ if (sp->polyomino[poly_no].attached)
+ return 0;
+
+ for (i=0;i<sp->polyomino[poly_no].len;i++) {
+ transform(sp->polyomino[poly_no].point[i],
+ sp->polyomino[poly_no].point[point_no],
+ sp->polyomino[poly_no].transform_list[transform_index]^(rot180<<1),
+ attach_point, &target_point);
+ if ( ! ((target_point.x>=0) && (target_point.x<sp->width)
+ && (target_point.y>=0) && (target_point.y<sp->height)
+ && (ARRAY_P(target_point) == -1))) {
+ if (sp->identical) {
+ attachable = 0;
+ if ((target_point.x>=0) && (target_point.x<sp->width)
+ && (target_point.y>=0) && (target_point.y<sp->height)
+ && (ARRAY_P(target_point) >= 0)
+ && (ARRAY_P(target_point)<worst_reason_not_to_attach))
+ worst_reason_not_to_attach = ARRAY_P(target_point);
+ }
+ else
+ return 0;
+ }
+ }
+
+ if (sp->identical && !attachable) {
+ if (worst_reason_not_to_attach < 1000000000)
+ reason_to_not_attach[worst_reason_not_to_attach] = 1;
+ return 0;
+ }
+
+ for (i=0;i<sp->polyomino[poly_no].len;i++) {
+ transform(sp->polyomino[poly_no].point[i],
+ sp->polyomino[poly_no].point[point_no],
+ sp->polyomino[poly_no].transform_list[transform_index]^(rot180<<1),
+ attach_point, &target_point);
+ ARRAY_P(target_point) = poly_no;
+ CHANGED_ARRAY_P(target_point) = 1;
+ }
+
+ sp->attach_list[sp->nr_attached] = poly_no;
+ sp->nr_attached++;
+
+ sp->polyomino[poly_no].attached = 1;
+ sp->polyomino[poly_no].point_no = point_no;
+ sp->polyomino[poly_no].attach_point = attach_point;
+ sp->polyomino[poly_no].transform_index = transform_index;
+
+ if (!sp->check_ok(sp)) {
+ detach(sp,&poly_no,&point_no,&transform_index,&attach_point,rot180);
+ return 0;
+ }
+
+ return 1;
+}
+
+static
+int next_attach_try(polyominoesstruct *sp, int *poly_no, int *point_no, int *transform_index)
+{
+
+ (*transform_index)++;
+ if (*transform_index>=sp->polyomino[*poly_no].transform_len) {
+ *transform_index = 0;
+ (*point_no)++;
+ if (*point_no>=sp->polyomino[*poly_no].len) {
+ *point_no = 0;
+ next_poly_no(sp,poly_no);
+ if (*poly_no>=sp->nr_polyominoes) {
+ *poly_no = first_poly_no(sp);
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+
+/*******************************************************
+Display routines.
+*******************************************************/
+
+static void
+draw_without_bitmaps(ModeInfo * mi, polyominoesstruct *sp)
+{
+ Display *display = MI_DISPLAY(mi);
+ Window window = MI_WINDOW(mi);
+ GC gc = MI_GC(mi);
+ int x,y,poly_no,nr_lines,nr_rectangles;
+
+ XSetLineAttributes(display,gc,sp->box/10+1,LineSolid,CapRound,JoinRound);
+
+ for (poly_no=-1;poly_no<sp->nr_polyominoes;poly_no++) {
+ nr_rectangles = 0;
+ for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++)
+ if (CHANGED_ARRAY(x,y) && ARRAY(x,y) == poly_no) {
+ sp->rectangles[nr_rectangles].x = sp->x_margin + sp->box*x;
+ sp->rectangles[nr_rectangles].y = sp->y_margin + sp->box*y;
+ sp->rectangles[nr_rectangles].width = sp->box;
+ sp->rectangles[nr_rectangles].height = sp->box;
+ nr_rectangles++;
+ }
+ if (poly_no == -1)
+ XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
+ else
+ XSetForeground(display, gc, sp->polyomino[poly_no].color);
+ XFillRectangles(display, window, gc, sp->rectangles, nr_rectangles);
+ }
+
+ XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
+
+ nr_lines = 0;
+ for (x=0;x<sp->width-1;x++) for (y=0;y<sp->height;y++) {
+ if (ARRAY(x,y) == -1 && ARRAY(x+1,y) == -1
+ && (CHANGED_ARRAY(x,y) || CHANGED_ARRAY(x+1,y))) {
+ sp->lines[nr_lines].x1 = sp->x_margin + sp->box*(x+1);
+ sp->lines[nr_lines].y1 = sp->y_margin + sp->box*y;
+ sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1);
+ sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1);
+ nr_lines++;
+ }
+ }
+ XDrawSegments(display, window, gc, sp->lines, nr_lines);
+
+ nr_lines = 0;
+ for (x=0;x<sp->width;x++) for (y=0;y<sp->height-1;y++) {
+ if (ARRAY(x,y) == -1 && ARRAY(x,y+1) == -1
+ && (CHANGED_ARRAY(x,y) || CHANGED_ARRAY(x,y+1))) {
+ sp->lines[nr_lines].x1 = sp->x_margin + sp->box*x;
+ sp->lines[nr_lines].y1 = sp->y_margin + sp->box*(y+1);
+ sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1);
+ sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1);
+ nr_lines++;
+ }
+ }
+ XDrawSegments(display, window, gc, sp->lines, nr_lines);
+
+ XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
+ XDrawRectangle(display, window, gc, sp->x_margin, sp->y_margin, sp->box*sp->width, sp->box*sp->height);
+
+ XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
+
+ nr_lines = 0;
+ for (x=0;x<sp->width-1;x++) for (y=0;y<sp->height;y++) {
+ if (ARRAY(x+1,y) != ARRAY(x,y)) {
+ sp->lines[nr_lines].x1 = sp->x_margin + sp->box*(x+1);
+ sp->lines[nr_lines].y1 = sp->y_margin + sp->box*y;
+ sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1);
+ sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1);
+ nr_lines++;
+ }
+ }
+ XDrawSegments(display, window, gc, sp->lines, nr_lines);
+
+ nr_lines = 0;
+ for (x=0;x<sp->width;x++) for (y=0;y<sp->height-1;y++) {
+ if (ARRAY(x,y+1) != ARRAY(x,y)) {
+ sp->lines[nr_lines].x1 = sp->x_margin + sp->box*x;
+ sp->lines[nr_lines].y1 = sp->y_margin + sp->box*(y+1);
+ sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1);
+ sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1);
+ nr_lines++;
+ }
+ }
+ XDrawSegments(display, window, gc, sp->lines, nr_lines);
+ XSetLineAttributes(display,gc,1,LineSolid,CapRound,JoinRound);
+}
+
+static void create_bitmaps(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int x,y,n;
+ char *data;
+
+ for (n=0;n<countof(sp->bitmaps);n++) {
+
+/* Avoid duplication of identical bitmaps. */
+ if (IS_LEFT_UP(n) && (IS_LEFT(n) || IS_UP(n)))
+ sp->bitmaps[n] = sp->bitmaps[n & ~LEFT_UP];
+ else if (IS_LEFT_DOWN(n) && (IS_LEFT(n) || IS_DOWN(n)))
+ sp->bitmaps[n] = sp->bitmaps[n & ~LEFT_DOWN];
+ else if (IS_RIGHT_UP(n) && (IS_RIGHT(n) || IS_UP(n)))
+ sp->bitmaps[n] = sp->bitmaps[n & ~RIGHT_UP];
+ else if (IS_RIGHT_DOWN(n) && (IS_RIGHT(n) || IS_DOWN(n)))
+ sp->bitmaps[n] = sp->bitmaps[n & ~RIGHT_DOWN];
+
+ else /* if (bitmap_needed(n)) */ {
+ data = (char *) malloc(sizeof(char)*(sp->box*ROUND8(sp->box)/8));
+ if (data == NULL) {
+ sp->use_bitmaps = 0;
+ return;
+ }
+
+ for (y=0;y<sp->box;y++) for (x=0;x<sp->box;x++) {
+ if (!sp->use3D) {
+#ifdef SMALL_BELLYBUTTON
+ if (x >= sp->box / 2 && x <= sp->box / 2 + 1 &&
+ y >= sp->box / 2 && y <= sp->box / 2 + 1)
+ NOTHALFBIT(n,x,y)
+ else
+#endif
+ HALFBIT(n,x,y)
+ } else if ((x>=y && x<=sp->box-y-1 && IS_UP(n))
+ || (x<=y && x<=sp->box-y-1 && y<sp->box/2 && !IS_LEFT(n))
+ || (x>=y && x>=sp->box-y-1 && y<sp->box/2 && !IS_RIGHT(n)))
+ SETBIT(n,x,y)
+ else if ((x<=y && x<=sp->box-y-1 && IS_LEFT(n))
+ || (x>=y && x<=sp->box-y-1 && x<sp->box/2 && !IS_UP(n))
+ || (x<=y && x>=sp->box-y-1 && x<sp->box/2 && !IS_DOWN(n)))
+ TWOTHIRDSBIT(n,x,y)
+ else if ((x>=y && x>=sp->box-y-1 && IS_RIGHT(n))
+ || (x>=y && x<=sp->box-y-1 && x>=sp->box/2 && !IS_UP(n))
+ || (x<=y && x>=sp->box-y-1 && x>=sp->box/2 && !IS_DOWN(n)))
+ HALFBIT(n,x,y)
+ else if ((x<=y && x>=sp->box-y-1 && IS_DOWN(n))
+ || (x<=y && x<=sp->box-y-1 && y>=sp->box/2 && !IS_LEFT(n))
+ || (x>=y && x>=sp->box-y-1 && y>=sp->box/2 && !IS_RIGHT(n)))
+ THIRDBIT(n,x,y)
+ }
+
+ if (IS_LEFT(n))
+ for (y=0;y<sp->box;y++) for (x=G;x<G+T;x++)
+ SETBIT(n,x,y)
+ if (IS_RIGHT(n))
+ for (y=0;y<sp->box;y++) for (x=G;x<G+T;x++)
+ SETBIT(n,sp->box-1-x,y)
+ if (IS_UP(n))
+ for (x=0;x<sp->box;x++) for (y=G;y<G+T;y++)
+ SETBIT(n,x,y)
+ if (IS_DOWN(n))
+ for (x=0;x<sp->box;x++) for (y=G;y<G+T;y++)
+ SETBIT(n,x,sp->box-1-y)
+ if (IS_LEFT(n))
+ for (y=0;y<sp->box;y++) for (x=0;x<G;x++)
+ RESBIT(n,x,y)
+ if (IS_RIGHT(n))
+ for (y=0;y<sp->box;y++) for (x=0;x<G;x++)
+ RESBIT(n,sp->box-1-x,y)
+ if (IS_UP(n))
+ for (x=0;x<sp->box;x++) for (y=0;y<G;y++)
+ RESBIT(n,x,y)
+ if (IS_DOWN(n))
+ for (x=0;x<sp->box;x++) for (y=0;y<G;y++)
+ RESBIT(n,x,sp->box-1-y)
+
+ if (IS_LEFT(n) && IS_UP(n))
+ for (x=G;x<=G+R;x++)
+ for (y=G;y<=R+2*G-x;y++) {
+ if (x+y>R+2*G-RT)
+ SETBIT(n,x,y)
+ else
+ RESBIT(n,x,y)
+ }
+ if (IS_LEFT(n) && IS_DOWN(n))
+ for (x=G;x<=G+R;x++)
+ for (y=G;y<=R+2*G-x;y++) {
+ if (x+y>R+2*G-RT)
+ SETBIT(n,x,sp->box-1-y)
+ else
+ RESBIT(n,x,sp->box-1-y)
+ }
+ if (IS_RIGHT(n) && IS_UP(n))
+ for (x=G;x<=G+R;x++)
+ for (y=G;y<=R+2*G-x;y++) {
+ if (x+y>R+2*G-RT)
+ SETBIT(n,sp->box-1-x,y)
+ else
+ RESBIT(n,sp->box-1-x,y)
+ }
+ if (IS_RIGHT(n) && IS_DOWN(n))
+ for (x=G;x<=G+R;x++)
+ for (y=G;y<=R+2*G-x;y++) {
+ if (x+y>R+2*G-RT)
+ SETBIT(n,sp->box-1-x,sp->box-1-y)
+ else
+ RESBIT(n,sp->box-1-x,sp->box-1-y)
+ }
+
+ if (!IS_LEFT(n) && !IS_UP(n) && IS_LEFT_UP(n)) {
+ for (x=0;x<G;x++) for(y=0;y<G;y++)
+ RESBIT(n,x,y)
+ for (x=G;x<G+T;x++) for(y=0;y<G;y++)
+ SETBIT(n,x,y)
+ for (x=0;x<G+T;x++) for(y=G;y<G+T;y++)
+ SETBIT(n,x,y)
+ }
+ if (!IS_LEFT(n) && !IS_DOWN(n) && IS_LEFT_DOWN(n)) {
+ for (x=0;x<G;x++) for(y=0;y<G;y++)
+ RESBIT(n,x,sp->box-1-y)
+ for (x=G;x<G+T;x++) for(y=0;y<G;y++)
+ SETBIT(n,x,sp->box-1-y)
+ for (x=0;x<G+T;x++) for(y=G;y<G+T;y++)
+ SETBIT(n,x,sp->box-1-y)
+ }
+ if (!IS_RIGHT(n) && !IS_UP(n) && IS_RIGHT_UP(n)) {
+ for (x=0;x<G;x++) for(y=0;y<G;y++)
+ RESBIT(n,sp->box-1-x,y)
+ for (x=G;x<G+T;x++) for(y=0;y<G;y++)
+ SETBIT(n,sp->box-1-x,y)
+ for (x=0;x<G+T;x++) for(y=G;y<G+T;y++)
+ SETBIT(n,sp->box-1-x,y)
+ }
+ if (!IS_RIGHT(n) && !IS_DOWN(n) && IS_RIGHT_DOWN(n)) {
+ for (x=0;x<G;x++) for(y=0;y<G;y++)
+ RESBIT(n,sp->box-1-x,sp->box-1-y)
+ for (x=G;x<G+T;x++) for(y=0;y<G;y++)
+ SETBIT(n,sp->box-1-x,sp->box-1-y)
+ for (x=0;x<G+T;x++) for(y=G;y<G+T;y++)
+ SETBIT(n,sp->box-1-x,sp->box-1-y)
+ }
+
+#ifdef LARGE_BELLYBUTTON
+ if (!sp->use3D) {
+ if (!IS_LEFT(n) && !IS_UP(n) && !IS_LEFT_UP(n))
+ for (x=0;x<G+T;x++) for(y=0;y<G+T;y++)
+ SETBIT(n,x,y)
+ if (!IS_LEFT(n) && !IS_DOWN(n) && !IS_LEFT_DOWN(n))
+ for (x=0;x<G+T;x++) for(y=sp->box-G-T;y<sp->box;y++)
+ SETBIT(n,x,y)
+ if (!IS_RIGHT(n) && !IS_UP(n) && !IS_RIGHT_UP(n))
+ for (x=sp->box-G-T;x<sp->box;x++) for(y=0;y<G+T;y++)
+ SETBIT(n,x,y)
+ if (!IS_RIGHT(n) && !IS_DOWN(n) && !IS_RIGHT_DOWN(n))
+ for (x=sp->box-G-T;x<sp->box;x++) for(y=sp->box-G-T;y<sp->box;y++)
+ SETBIT(n,x,y)
+ } else
+#else
+ if (sp->use3D)
+#endif
+ {
+ if (!IS_LEFT(n) && !IS_UP(n) && !IS_LEFT_UP(n))
+ for (x=0;x<sp->box/2-RR;x++) for(y=0;y<sp->box/2-RR;y++)
+ THREEQUARTERSBIT(n,x,y)
+ if (!IS_LEFT(n) && !IS_DOWN(n) && !IS_LEFT_DOWN(n))
+ for (x=0;x<sp->box/2-RR;x++) for(y=sp->box/2+RR;y<sp->box;y++)
+ THREEQUARTERSBIT(n,x,y)
+ if (!IS_RIGHT(n) && !IS_UP(n) && !IS_RIGHT_UP(n))
+ for (x=sp->box/2+RR;x<sp->box;x++) for(y=0;y<sp->box/2-RR;y++)
+ THREEQUARTERSBIT(n,x,y)
+ if (!IS_RIGHT(n) && !IS_DOWN(n) && !IS_RIGHT_DOWN(n))
+ for (x=sp->box/2+RR;x<sp->box;x++) for(y=sp->box/2+RR;y<sp->box;y++)
+ THREEQUARTERSBIT(n,x,y)
+ }
+
+ sp->bitmaps[n] = XCreateImage(MI_DISPLAY(mi), MI_VISUAL(mi), 1, XYBitmap,
+ 0, data, sp->box, sp->box, 8, 0);
+ if (sp->bitmaps[n] == None) {
+ free(data);
+ sp->use_bitmaps = 0;
+ return;
+ }
+ sp->bitmaps[n]->byte_order = MSBFirst;
+ sp->bitmaps[n]->bitmap_unit = 8;
+ sp->bitmaps[n]->bitmap_bit_order = LSBFirst;
+ }
+ }
+
+ sp->use_bitmaps = 1;
+}
+
+static void draw_with_bitmaps(ModeInfo * mi, polyominoesstruct *sp)
+{
+ Display *display = MI_DISPLAY(mi);
+ Window window = MI_WINDOW(mi);
+ GC gc = MI_GC(mi);
+ int x,y,t,bitmap_index;
+
+ for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) {
+ if (ARRAY(x,y) == -1) {
+ if (CHANGED_ARRAY(x,y)) {
+ XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
+ XFillRectangle(display,window,gc,
+ sp->x_margin + sp->box*x,
+ sp->y_margin + sp->box*y,
+ sp->box,sp->box);
+ }
+ }
+ else {
+ XSetForeground(display, gc, sp->polyomino[ARRAY(x,y)].color);
+ bitmap_index = 0;
+ if (ARR(x,y) != ARR(x-1,y)) bitmap_index |= LEFT;
+ if (ARR(x,y) != ARR(x+1,y)) bitmap_index |= RIGHT;
+ if (ARR(x,y) != ARR(x,y-1)) bitmap_index |= UP;
+ if (ARR(x,y) != ARR(x,y+1)) bitmap_index |= DOWN;
+ if (ARR(x,y) != ARR(x-1,y-1)) bitmap_index |= LEFT_UP;
+ if (ARR(x,y) != ARR(x-1,y+1)) bitmap_index |= LEFT_DOWN;
+ if (ARR(x,y) != ARR(x+1,y-1)) bitmap_index |= RIGHT_UP;
+ if (ARR(x,y) != ARR(x+1,y+1)) bitmap_index |= RIGHT_DOWN;
+ (void) XPutImage(display,window,gc,
+ sp->bitmaps[bitmap_index],
+ 0,0,
+ sp->x_margin + sp->box*x,
+ sp->y_margin + sp->box*y,
+ sp->box,sp->box);
+ }
+ }
+
+ XSetForeground(display, gc, sp->border_color);
+ for (t=G;t<G+T;t++)
+ XDrawRectangle(display,window,gc,
+ sp->x_margin-t-1,sp->y_margin-t-1,
+ sp->box*sp->width+1+2*t, sp->box*sp->height+1+2*t);
+}
+
+
+/***************************************************
+Routines to initialise and close down polyominoes.
+***************************************************/
+
+static void free_bitmaps(polyominoesstruct *sp)
+{
+ int n;
+
+ for (n=0;n<countof(sp->bitmaps);n++)
+/* Don't bother to free duplicates */
+ if (IS_LEFT_UP(n) && (IS_LEFT(n) || IS_UP(n)))
+ sp->bitmaps[n] = None;
+ else if (IS_LEFT_DOWN(n) && (IS_LEFT(n) || IS_DOWN(n)))
+ sp->bitmaps[n] = None;
+ else if (IS_RIGHT_UP(n) && (IS_RIGHT(n) || IS_UP(n)))
+ sp->bitmaps[n] = None;
+ else if (IS_RIGHT_DOWN(n) && (IS_RIGHT(n) || IS_DOWN(n)))
+ sp->bitmaps[n] = None;
+
+ else if (sp->bitmaps[n] != None) {
+ XDestroyImage(sp->bitmaps[n]);
+ sp->bitmaps[n] = None;
+ }
+}
+
+#define deallocate(p,t) if ((p)!=NULL) {free(p); p=(t*)NULL;}
+
+ENTRYPOINT void free_polyominoes(ModeInfo * mi)
+{
+ polyominoesstruct *sp = &polyominoeses[MI_SCREEN(mi)];
+ int n;
+
+ for (n=0;n<sp->nr_polyominoes;n++) {
+ deallocate(sp->polyomino[n].point, point_type);
+ }
+
+ deallocate(sp->polyomino, polyomino_type);
+ deallocate(sp->attach_list, int);
+ deallocate(sp->rectangles, XRectangle);
+ deallocate(sp->lines, XSegment);
+ deallocate(sp->reason_to_not_attach, int);
+ deallocate(sp->array, int);
+ deallocate(sp->changed_array, int);
+
+ free_bitmaps(sp);
+}
+
+#define set_allocate(p,type,size) p = (type *) malloc(size); \
+ if ((p)==NULL) {free_polyominoes(mi);return 0;}
+
+#define copy_polyomino(dst,src,new_rand) \
+ (dst).len=(src).len; \
+ (dst).max_white = (src).max_white; \
+ set_allocate((dst).point,point_type,sizeof(point_type)*(src).len); \
+ (dst).len = (src).len; \
+ if (new_rand) \
+ random_permutation((src).len,perm_point); \
+ for (i=0;i<(src).len;i++) \
+ (dst).point[i] = (src).point[perm_point[i]]; \
+ (dst).transform_len = (src).transform_len; \
+ if (new_rand) \
+ random_permutation((src).transform_len,perm_transform); \
+ for (i=0;i<(src).transform_len;i++) \
+ (dst).transform_list[i] = (src).transform_list[perm_transform[i]]; \
+ (dst).attached = 0
+
+
+/***************************************************
+Puzzle specific initialization routines.
+***************************************************/
+
+static
+int check_pentomino_puzzle(polyominoesstruct *sp)
+{
+ return check_all_regions_multiple_of(sp, 5) && whites_ok(sp);
+}
+
+static
+int check_hexomino_puzzle(polyominoesstruct *sp)
+{
+ return check_all_regions_multiple_of(sp, 6) && whites_ok(sp);
+}
+
+static
+int check_tetr_pentomino_puzzle(polyominoesstruct *sp)
+{
+ return check_all_regions_positive_combination_of(sp, 5, 4) && whites_ok(sp);
+}
+
+static
+int check_pent_hexomino_puzzle(polyominoesstruct *sp)
+{
+ return check_all_regions_positive_combination_of(sp, 6, 5) && whites_ok(sp);
+}
+
+static
+int check_heptomino_puzzle(polyominoesstruct *sp)
+{
+ return check_all_regions_multiple_of(sp, 7) && whites_ok(sp);
+}
+
+static
+int check_octomino_puzzle(polyominoesstruct *sp)
+{
+ return check_all_regions_multiple_of(sp, 8) && whites_ok(sp);
+}
+
+static
+int check_dekomino_puzzle(polyominoesstruct *sp)
+{
+ return check_all_regions_multiple_of(sp, 10) && whites_ok(sp);
+}
+
+static
+int check_elevenomino_puzzle(polyominoesstruct *sp)
+{
+ return check_all_regions_multiple_of(sp, 11) && whites_ok(sp);
+}
+
+static struct {int len; point_type point[4];
+ int transform_len, transform_list[8], max_white;} tetromino[5] =
+{
+/*
+xxxx
+*/
+ {4, {{0,0}, {1,0}, {2,0}, {3,0}},
+ 2, {0, 1, -1, -1, -1, -1, -1, -1}, 2},
+/*
+xxx
+ x
+*/
+ {4, {{0,0}, {1,0}, {2,0}, {2,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 2},
+/*
+xxx
+ x
+*/
+ {4, {{0,0}, {1,0}, {1,1}, {2,0}},
+ 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
+/*
+xx
+ xx
+*/
+ {4, {{0,0}, {1,0}, {1,1}, {2,1}},
+ 4, {0, 1, 4, 5, -1, -1, -1, -1}, 2},
+/*
+xx
+xx
+*/
+ {4, {{0,0}, {0,1}, {1,0}, {1,1}},
+ 1, {0, -1, -1, -1, -1, -1, -1, -1}, 2}};
+
+
+static struct pentomino_struct {int len; point_type point[5];
+ int transform_len, transform_list[8], max_white;}
+ pentomino[12] =
+{
+/*
+xxxxx
+*/
+ {5, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}},
+ 2, {0, 1, -1, -1, -1, -1, -1, -1}, 3},
+/*
+xxxx
+ x
+*/
+ {5, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+xxxx
+ x
+*/
+ {5, {{0,0}, {1,0}, {2,0}, {2,1}, {3,0}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+ x
+xxx
+ x
+*/
+ {5, {{0,0}, {1,0}, {2,-1}, {2,0}, {2,1}},
+ 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
+/*
+xxx
+ xx
+*/
+ {5, {{0,0}, {1,0}, {2,0}, {2,1}, {3,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+xxx
+ xx
+*/
+ {5, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+xxx
+ x
+ x
+*/
+ {5, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}},
+ 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
+/*
+ x
+xxx
+ x
+*/
+ {5, {{0,0}, {1,-1}, {1,0}, {2,0}, {2,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+xxx
+x x
+*/
+ {5, {{0,0}, {0,1}, {1,0}, {2,0}, {2,1}},
+ 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
+/*
+ x
+xxx
+x
+*/
+ {5, {{0,0}, {0,1}, {1,0}, {2,-1}, {2,0}},
+ 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3},
+/*
+ x
+xxx
+ x
+*/
+ {5, {{0,0}, {1,-1}, {1,0}, {1,1}, {2,0}},
+ 1, {0, -1, -1, -1, -1, -1, -1, -1}, 4},
+/*
+xx
+ xx
+ x
+*/
+ {5, {{0,0}, {1,0}, {1,1}, {2,1}, {2,2}},
+ 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3}};
+
+
+static struct hexomino_struct {int len; point_type point[6];
+ int transform_len, transform_list[8], max_white;}
+ hexomino[35] =
+{
+/*
+xxxxxx
+*/
+ {6, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {5,0}},
+ 2, {0, 1, -1, -1, -1, -1, -1, -1}, 3},
+/*
+xxxxx
+ x
+*/
+ {6, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {4,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+xxxxx
+ x
+*/
+ {6, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}, {4,0}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
+/*
+xxxxx
+ x
+*/
+ {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,0}, {4,0}},
+ 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
+/*
+ x
+xxxx
+ x
+*/
+ {6, {{0,0}, {1,0}, {2,0}, {3,-1}, {3,0}, {3,1}},
+ 4, {0, 1, 2, 3, -1, -1, -1, -1}, 4},
+/*
+xxxx
+ xx
+*/
+ {6, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}, {4,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+xxxx
+ xx
+*/
+ {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,0}, {3,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+xxxx
+ x
+ x
+*/
+ {6, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}, {3,2}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+ x
+xxxx
+ x
+*/
+ {6, {{0,0}, {1,0}, {2,-1}, {2,0}, {3,0}, {3,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+xxxx
+ x x
+*/
+ {6, {{0,0}, {1,0}, {1,1}, {2,0}, {3,0}, {3,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
+/*
+ x
+xxxx
+ x
+*/
+ {6, {{0,0}, {1,-1}, {1,0}, {2,0}, {3,0}, {3,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
+/*
+xxxx
+x x
+*/
+ {6, {{0,0}, {0,1}, {1,0}, {2,0}, {3,0}, {3,1}},
+ 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
+/*
+ x
+xxxx
+x
+*/
+ {6, {{0,0}, {0,1}, {1,0}, {2,0}, {3,-1}, {3,0}},
+ 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3},
+/*
+ x
+xxxx
+ x
+*/
+ {6, {{0,0}, {1,0}, {2,-1}, {2,0}, {2,1}, {3,0}},
+ 4, {0, 1, 2, 3, -1, -1, -1, -1}, 4},
+/*
+xxxx
+ xx
+*/
+ {6, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}, {3,0}},
+ 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
+/*
+xxxx
+ x
+ x
+*/
+ {6, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}, {3,0}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+ x
+xxxx
+ x
+*/
+ {6, {{0,0}, {1,-1}, {1,0}, {2,0}, {2,1}, {3,0}},
+ 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3},
+/*
+ xx
+xxx
+ x
+*/
+ {6, {{0,0}, {1,0}, {2,-1}, {2,0}, {2,1}, {3,-1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+ xx
+xxx
+ x
+*/
+ {6, {{0,0}, {1,-1}, {1,0}, {2,-1}, {2,0}, {2,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+ x
+xxx
+x x
+*/
+ {6, {{0,0}, {0,1}, {1,0}, {2,-1}, {2,0}, {2,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
+/*
+xxx
+ xxx
+*/
+ {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,1}, {4,1}},
+ 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3},
+/*
+xxx
+ xx
+ x
+*/
+ {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,1}, {3,2}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+xxx
+ xxx
+*/
+ {6, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}, {3,1}},
+ 4, {0, 1, 4, 5, -1, -1, -1, -1}, 4},
+/*
+xxx
+ xx
+ x
+*/
+ {6, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}, {3,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
+/*
+ x
+xxx
+ xx
+*/
+ {6, {{0,0}, {1,-1}, {1,0}, {2,0}, {2,1}, {3,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
+/*
+xxx
+x xx
+*/
+ {6, {{0,0}, {0,1}, {1,0}, {2,0}, {2,1}, {3,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+xxx
+ xx
+ x
+*/
+ {6, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}, {2,2}},
+ 4, {0, 1, 2, 3, -1, -1, -1, -1}, 4},
+/*
+ x
+xxx
+ xx
+*/
+ {6, {{0,0}, {1,-1}, {1,0}, {1,1}, {2,0}, {2,1}},
+ 4, {0, 1, 2, 3, -1, -1, -1, -1}, 4},
+/*
+xxx
+xxx
+*/
+ {6, {{0,0}, {0,1}, {1,0}, {1,1}, {2,0}, {2,1}},
+ 2, {0, 1, -1, -1, -1, -1, -1, -1}, 3},
+/*
+xxx
+ x
+ xx
+*/
+ {6, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}, {3,2}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+xxx
+ x
+ xx
+*/
+ {6, {{0,0}, {1,0}, {1,2}, {2,0}, {2,1}, {2,2}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+ x
+xxx
+x x
+*/
+ {6, {{0,0}, {0,1}, {1,-1}, {1,0}, {2,0}, {2,1}},
+ 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
+/*
+ xx
+xxx
+x
+*/
+ {6, {{0,0}, {0,1}, {1,0}, {2,-1}, {2,0}, {3,-1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+ xx
+xxx
+x
+*/
+ {6, {{0,0}, {0,1}, {1,-1}, {1,0}, {2,-1}, {2,0}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
+/*
+xx
+ xx
+ xx
+*/
+ {6, {{0,0}, {1,0}, {1,1}, {2,1}, {2,2}, {3,2}},
+ 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3}};
+
+static struct pentomino_struct one_sided_pentomino[60];
+
+static void make_one_sided_pentomino(void)
+{
+ int i,j,t,u;
+
+ j=0;
+ for (i=0;i<countof(pentomino);i++) {
+ one_sided_pentomino[j] = pentomino[i];
+ for (t=0;t<8;t++)
+ if (one_sided_pentomino[j].transform_list[t]>=4) {
+ one_sided_pentomino[j].transform_len = t;
+ j++;
+ one_sided_pentomino[j] = pentomino[i];
+ for (u=t;u<8;u++) one_sided_pentomino[j].transform_list[u-t] = one_sided_pentomino[j].transform_list[u];
+ one_sided_pentomino[j].transform_len -= t;
+ break;
+ }
+ j++;
+ }
+}
+
+static struct hexomino_struct one_sided_hexomino[60];
+
+static void make_one_sided_hexomino(void)
+{
+ int i,j,t,u;
+
+ j=0;
+ for (i=0;i<countof(hexomino);i++) {
+ one_sided_hexomino[j] = hexomino[i];
+ for (t=0;t<8;t++)
+ if (one_sided_hexomino[j].transform_list[t]>=4) {
+ one_sided_hexomino[j].transform_len = t;
+ j++;
+ one_sided_hexomino[j] = hexomino[i];
+ for (u=t;u<8;u++) one_sided_hexomino[j].transform_list[u-t] = one_sided_hexomino[j].transform_list[u];
+ one_sided_hexomino[j].transform_len -= t;
+ break;
+ }
+ j++;
+ }
+}
+
+/*
+Find all the ways of placing all twelve pentominoes
+into a rectangle whose size is 20x3, 15x4, 12x5 or 10x6.
+*/
+
+static
+int set_pentomino_puzzle(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_poly[12], perm_point[5], perm_transform[8], i, p;
+
+ switch (NRAND(4)) {
+ case 0:
+ sp->width = 20;
+ sp->height = 3;
+ break;
+ case 1:
+ sp->width = 15;
+ sp->height = 4;
+ break;
+ case 2:
+ sp->width = 12;
+ sp->height = 5;
+ break;
+ case 3:
+ sp->width = 10;
+ sp->height = 6;
+ break;
+ }
+
+ sp->nr_polyominoes = 12;
+ set_allocate(sp->polyomino,polyomino_type,
+ sp->nr_polyominoes*sizeof(polyomino_type));
+ random_permutation(sp->nr_polyominoes,perm_poly);
+ for (p=0;p<sp->nr_polyominoes;p++) {
+ copy_polyomino(sp->polyomino[p],pentomino[perm_poly[p]],1);
+ }
+
+ sp->check_ok = check_pentomino_puzzle;
+
+ return 1;
+}
+
+/*
+Many of the following puzzles are inspired by
+http://www.xs4all.nl/~gp/PolyominoSolver/Polyomino.html
+*/
+
+/*
+Find all the ways of placing all eighteen one-sided pentominoes
+into a rectangle.
+*/
+
+static
+int set_one_sided_pentomino_puzzle(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_poly[18], perm_point[5], perm_transform[8], i, p;
+
+ make_one_sided_pentomino();
+
+ switch (NRAND(4)) {
+ case 0:
+ sp->width = 30;
+ sp->height = 3;
+ break;
+ case 1:
+ sp->width = 18;
+ sp->height = 5;
+ break;
+ case 2:
+ sp->width = 15;
+ sp->height = 6;
+ break;
+ case 3:
+ sp->width = 10;
+ sp->height = 9;
+ break;
+ }
+
+ sp->nr_polyominoes = 18;
+ set_allocate(sp->polyomino,polyomino_type,
+ sp->nr_polyominoes*sizeof(polyomino_type));
+ random_permutation(sp->nr_polyominoes,perm_poly);
+ for (p=0;p<sp->nr_polyominoes;p++) {
+ copy_polyomino(sp->polyomino[p],one_sided_pentomino[perm_poly[p]],1);
+ }
+
+ sp->check_ok = check_pentomino_puzzle;
+
+ return 1;
+}
+
+/*
+Find all the ways of placing all sixty one-sided hexominoes
+into a rectangle.
+*/
+
+static
+int set_one_sided_hexomino_puzzle(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_poly[60], perm_point[6], perm_transform[8], i, p;
+
+ make_one_sided_hexomino();
+
+ switch (NRAND(8)) {
+ case 0:
+ sp->width = 20;
+ sp->height = 18;
+ break;
+ case 1:
+ sp->width = 24;
+ sp->height = 15;
+ break;
+ case 2:
+ sp->width = 30;
+ sp->height = 12;
+ break;
+ case 3:
+ sp->width = 36;
+ sp->height = 10;
+ break;
+ case 4:
+ sp->width = 40;
+ sp->height = 9;
+ break;
+ case 5:
+ sp->width = 45;
+ sp->height = 8;
+ break;
+ case 6:
+ sp->width = 60;
+ sp->height = 6;
+ break;
+ case 7:
+ sp->width = 72;
+ sp->height = 5;
+ break;
+ }
+
+ sp->nr_polyominoes = 60;
+ set_allocate(sp->polyomino,polyomino_type,
+ sp->nr_polyominoes*sizeof(polyomino_type));
+ random_permutation(sp->nr_polyominoes,perm_poly);
+ for (p=0;p<sp->nr_polyominoes;p++) {
+ copy_polyomino(sp->polyomino[p],one_sided_hexomino[perm_poly[p]],1);
+ }
+
+ sp->check_ok = check_hexomino_puzzle;
+
+ return 1;
+}
+
+/*
+Find all the ways of placing all five tetrominoes and all twelve
+pentominoes into a rectangle.
+*/
+
+static
+int set_tetr_pentomino_puzzle(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_poly[17], perm_point[5], perm_transform[8], i, p;
+
+ switch (NRAND(3)) {
+ case 0:
+ sp->width = 20;
+ sp->height = 4;
+ break;
+ case 1:
+ sp->width = 16;
+ sp->height = 5;
+ break;
+ case 2:
+ sp->width = 10;
+ sp->height = 8;
+ break;
+ }
+
+ sp->nr_polyominoes = 17;
+ set_allocate(sp->polyomino,polyomino_type,
+ sp->nr_polyominoes*sizeof(polyomino_type));
+ random_permutation(sp->nr_polyominoes,perm_poly);
+ for (p=0;p<countof(tetromino);p++) {
+ copy_polyomino(sp->polyomino[perm_poly[p]],tetromino[p],1);
+ }
+ for (p=0;p<countof(pentomino);p++) {
+ copy_polyomino(sp->polyomino[perm_poly[p+5]],pentomino[p],1);
+ }
+
+ sp->check_ok = check_tetr_pentomino_puzzle;
+
+ return 1;
+}
+/*
+Find all the ways of placing all twelve pentominoes and all thirty five
+hexominoes into a rectangle whose size is 18x15.
+*/
+
+static
+int set_pent_hexomino_puzzle(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_poly[47], perm_point[6], perm_transform[8], i, p;
+
+ switch (NRAND(5)) {
+ case 0:
+ sp->width = 54;
+ sp->height = 5;
+ break;
+ case 1:
+ sp->width = 45;
+ sp->height = 6;
+ break;
+ case 2:
+ sp->width = 30;
+ sp->height = 9;
+ break;
+ case 3:
+ sp->width = 27;
+ sp->height = 10;
+ break;
+ case 4:
+ sp->width = 18;
+ sp->height = 15;
+ break;
+ }
+
+ sp->nr_polyominoes = 47;
+ set_allocate(sp->polyomino,polyomino_type,47*sizeof(polyomino_type));
+ random_permutation(47,perm_poly);
+ for (p=0;p<countof(pentomino);p++) {
+ copy_polyomino(sp->polyomino[perm_poly[p]],pentomino[p],1);
+ }
+ for (p=0;p<countof(hexomino);p++) {
+ copy_polyomino(sp->polyomino[perm_poly[p+12]],hexomino[p],1);
+ }
+
+ sp->check_ok = check_pent_hexomino_puzzle;
+
+ return 1;
+}
+
+/*
+Other puzzles:
+
+Science News September 20, 1986 Vol 130, No 12
+Science News November 14, 1987 Vol 132, Pg 310
+*/
+
+/*
+
+ *
+**** fills a 10x5 rectangle
+
+*/
+
+static struct {int len; point_type point[5];
+ int transform_len, transform_list[8], max_white;} pentomino1 =
+ {5, {{0,0}, {1,0}, {2,0}, {3,0}, {1,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3};
+
+static
+int set_pentomino_puzzle1(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_point[5], perm_transform[8], i, p;
+
+ sp->width = 10;
+ sp->height =5;
+
+ sp->nr_polyominoes = 10;
+ set_allocate(sp->polyomino,polyomino_type,
+ sp->nr_polyominoes*sizeof(polyomino_type));
+ for (p=0;p<sp->nr_polyominoes;p++) {
+ copy_polyomino(sp->polyomino[p],pentomino1,1);
+ }
+
+ sp->check_ok = check_pentomino_puzzle;
+
+ return 1;
+}
+
+/*
+
+ *
+***** fills a 24x23 rectangle
+
+*/
+
+static struct {int len; point_type point[6];
+ int transform_len, transform_list[8], max_white;} hexomino1 =
+ {6, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {1,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4};
+
+static
+int set_hexomino_puzzle1(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_point[6], perm_transform[8], i, p;
+
+ sp->width = 24;
+ sp->height =23;
+
+ sp->nr_polyominoes = 92;
+ set_allocate(sp->polyomino,polyomino_type,
+ sp->nr_polyominoes*sizeof(polyomino_type));
+ for (p=0;p<sp->nr_polyominoes;p++) {
+ copy_polyomino(sp->polyomino[p],hexomino1,1);
+ }
+
+ sp->check_ok = check_hexomino_puzzle;
+
+ return 1;
+}
+
+/*
+
+ **
+***** fills a 21x26 rectangle
+
+(All solutions have 180 degree rotational symmetry)
+
+*/
+
+static struct {int len; point_type point[7];
+ int transform_len, transform_list[8], max_white;} heptomino1 =
+ {7, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {1,1}, {2,1}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4};
+
+static
+int set_heptomino_puzzle1(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_point[7], perm_transform[8], i, p;
+
+ sp->rot180 = 1;
+
+ sp->width = 26;
+ sp->height =21;
+
+ sp->nr_polyominoes = 78;
+ set_allocate(sp->polyomino,polyomino_type,
+ sp->nr_polyominoes*sizeof(polyomino_type));
+ for (p=0;p<sp->nr_polyominoes;p+=2) {
+ copy_polyomino(sp->polyomino[p],heptomino1,1);
+ copy_polyomino(sp->polyomino[p+1],heptomino1,0);
+ }
+
+ sp->check_ok = check_heptomino_puzzle;
+
+ return 1;
+}
+
+/* The following puzzles from
+Polyominoes Puzzles, Patterns, Problems, and Packings Revised (2nd) Edition
+by Solomon W. Golomb Princeton University Press 1994
+*/
+
+/*
+
+ **
+***** fills a 28x19 rectangle
+
+*/
+static
+int set_heptomino_puzzle2(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_point[7], perm_transform[8], i, p;
+
+ sp->width = 28;
+ sp->height =19;
+
+ sp->nr_polyominoes = 76;
+ set_allocate(sp->polyomino,polyomino_type,
+ sp->nr_polyominoes*sizeof(polyomino_type));
+ for (p=0;p<sp->nr_polyominoes;p++) {
+ copy_polyomino(sp->polyomino[p],heptomino1,1);
+ }
+
+ sp->check_ok = check_heptomino_puzzle;
+
+ return 1;
+}
+
+/*
+
+***
+**** fills a 25x22 rectangle
+****
+
+*/
+
+static struct {int len; point_type point[11];
+ int transform_len, transform_list[8], max_white;} elevenomino1 =
+ {11, {{0,0}, {1,0}, {2,0},
+ {0,1}, {1,1}, {2,1}, {3,1},
+ {0,2}, {1,2}, {2,2}, {3,2}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 6};
+
+static
+int set_elevenomino_puzzle1(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_point[11], perm_transform[8], i, p;
+
+ sp->rot180 = 1;
+
+ sp->width = 25;
+ sp->height =22;
+
+ sp->nr_polyominoes = 50;
+ set_allocate(sp->polyomino,polyomino_type,
+ sp->nr_polyominoes*sizeof(polyomino_type));
+ for (p=0;p<sp->nr_polyominoes;p+=2) {
+ copy_polyomino(sp->polyomino[p],elevenomino1,1);
+ copy_polyomino(sp->polyomino[p+1],elevenomino1,0);
+ }
+
+ sp->check_ok = check_elevenomino_puzzle;
+
+ return 1;
+}
+
+/*
+
+ *
+ *
+**** fills 32 x 30 rectangle
+****
+
+*/
+
+static struct {int len; point_type point[10];
+ int transform_len, transform_list[8], max_white;} dekomino1 =
+ {10, { {1,-1},
+ {1,0},
+ {0,1}, {1,1}, {2,1}, {3,1},
+ {0,2}, {1,2}, {2,2}, {3,2}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 5};
+
+static
+int set_dekomino_puzzle1(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_point[10], perm_transform[8], i, p;
+
+ sp->width = 32;
+ sp->height =30;
+
+ sp->nr_polyominoes = 96;
+ set_allocate(sp->polyomino,polyomino_type,
+ sp->nr_polyominoes*sizeof(polyomino_type));
+ for (p=0;p<sp->nr_polyominoes;p++) {
+ copy_polyomino(sp->polyomino[p],dekomino1,1);
+ }
+
+ sp->check_ok = check_dekomino_puzzle;
+
+ return 1;
+}
+
+/*
+
+ *
+*** fills 96 x 26 rectangle
+****
+
+*/
+
+static struct {int len; point_type point[10];
+ int transform_len, transform_list[8], max_white;} octomino1 =
+ {8, { {1,0},
+ {0,1}, {1,1}, {2,1},
+ {0,2}, {1,2}, {2,2}, {3,2}},
+ 8, {0, 1, 2, 3, 4, 5, 6, 7}, 5};
+
+static
+int set_octomino_puzzle1(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_point[8], perm_transform[8], i, p;
+
+ sp->width = 96;
+ sp->height =26;
+
+ sp->nr_polyominoes = 312;
+ set_allocate(sp->polyomino,polyomino_type,
+ sp->nr_polyominoes*sizeof(polyomino_type));
+ for (p=0;p<sp->nr_polyominoes;p++) {
+ copy_polyomino(sp->polyomino[p],octomino1,1);
+ }
+
+ sp->check_ok = check_octomino_puzzle;
+
+ return 1;
+}
+
+/*
+
+ * fills 15 x 15 rectangle
+****
+
+*/
+
+static
+int set_pentomino_puzzle2(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_point[5], perm_transform[8], i, p;
+
+ sp->width = 15;
+ sp->height =15;
+
+ sp->nr_polyominoes = 45;
+ set_allocate(sp->polyomino,polyomino_type,
+ sp->nr_polyominoes*sizeof(polyomino_type));
+ for (p=0;p<sp->nr_polyominoes;p++) {
+ copy_polyomino(sp->polyomino[p],pentomino1,1);
+ }
+
+ sp->check_ok = check_pentomino_puzzle;
+
+ return 1;
+}
+
+/*
+
+***
+**** fills a 47x33 rectangle
+****
+
+*/
+
+static
+int set_elevenomino_puzzle2(ModeInfo * mi, polyominoesstruct *sp)
+{
+ int perm_point[11], perm_transform[8], i, p;
+
+ sp->width = 47;
+ sp->height =33;
+
+ sp->nr_polyominoes = 141;
+ set_allocate(sp->polyomino,polyomino_type,
+ sp->nr_polyominoes*sizeof(polyomino_type));
+ for (p=0;p<sp->nr_polyominoes;p++) {
+ copy_polyomino(sp->polyomino[p],elevenomino1,1);
+ }
+
+ sp->check_ok = check_elevenomino_puzzle;
+
+ return 1;
+}
+
+/**************************************************
+The main functions.
+**************************************************/
+
+#define allocate(p,type,size) p = (type *) malloc(size); if ((p)==NULL) {free_polyominoes(mi); return;}
+
+ENTRYPOINT void
+init_polyominoes (ModeInfo * mi)
+{
+ polyominoesstruct *sp;
+ int i,x,y, start;
+ int box1, box2;
+ int *perm;
+
+ MI_INIT (mi, polyominoeses);
+ sp = &polyominoeses[MI_SCREEN(mi)];
+
+ sp->rot180 = 0;
+ sp->counter = 0;
+
+ if (MI_IS_FULLRANDOM(mi)) {
+ sp->identical = (Bool) (LRAND() & 1);
+ sp->use3D = (Bool) (NRAND(4));
+ } else {
+ sp->identical = identical;
+ sp->use3D = !plain;
+ }
+ if (sp->identical) {
+ switch (NRAND(9)) {
+ case 0:
+ if (!set_pentomino_puzzle1(mi, sp))
+ return;
+ break;
+ case 1:
+ if (!set_hexomino_puzzle1(mi, sp))
+ return;
+ break;
+ case 2:
+ if (!set_heptomino_puzzle1(mi, sp))
+ return;
+ break;
+ case 3:
+ if (!set_heptomino_puzzle2(mi, sp))
+ return;
+ break;
+ case 4:
+ if (!set_elevenomino_puzzle1(mi, sp))
+ return;
+ break;
+ case 5:
+ if (!set_dekomino_puzzle1(mi, sp))
+ return;
+ break;
+ case 6:
+ if (!set_octomino_puzzle1(mi, sp))
+ return;
+ break;
+ case 7:
+ if (!set_pentomino_puzzle2(mi, sp))
+ return;
+ break;
+ case 8:
+ if (!set_elevenomino_puzzle2(mi, sp))
+ return;
+ break;
+ }
+ } else {
+ switch (NRAND(5)) {
+ case 0:
+ if (!set_pentomino_puzzle(mi, sp))
+ return;
+ break;
+ case 1:
+ if (!set_one_sided_pentomino_puzzle(mi, sp))
+ return;
+ break;
+ case 2:
+ if (!set_one_sided_hexomino_puzzle(mi, sp))
+ return;
+ break;
+ case 3:
+ if (!set_pent_hexomino_puzzle(mi, sp))
+ return;
+ break;
+ case 4:
+ if (!set_tetr_pentomino_puzzle(mi, sp))
+ return;
+ break;
+ }
+ }
+
+ if (MI_HEIGHT(mi) > MI_WIDTH(mi)) { /* rotate if portrait */
+ int swap = sp->height;
+ sp->height = sp->width;
+ sp->width = swap;
+ }
+
+ allocate(sp->attach_list,int,sp->nr_polyominoes*sizeof(int));
+ sp->nr_attached = 0;
+
+ if (sp->identical) {
+ allocate(sp->reason_to_not_attach,int,sp->nr_polyominoes*sp->nr_polyominoes*sizeof(int));
+ }
+
+ allocate(sp->array,int,sp->width*sp->height*sizeof(int));
+ allocate(sp->changed_array,int,sp->width*sp->height*sizeof(int));
+ for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) ARRAY(x,y) = -1;
+
+ sp->left_right = NRAND(2);
+ sp->top_bottom = NRAND(2);
+
+ box1 = MI_WIDTH(mi)/(sp->width+2);
+ box2 = MI_HEIGHT(mi)/(sp->height+2);
+ if (box1<box2)
+ sp->box = box1;
+ else
+ sp->box = box2;
+
+ if (MI_WIDTH(mi) > MI_HEIGHT(mi) * 5 || /* weird window aspect ratio */
+ MI_HEIGHT(mi) > MI_WIDTH(mi)* 5) {
+ sp->box *= (MI_WIDTH(mi) > MI_HEIGHT(mi)
+ ? MI_WIDTH(mi) / (double) MI_HEIGHT(mi)
+ : MI_HEIGHT(mi) / (double) MI_WIDTH(mi));
+ }
+
+ if (sp->box >= 12) {
+ sp->box = (sp->box/12)*12;
+ create_bitmaps(mi,sp);
+ if (!sp->use_bitmaps)
+ free_bitmaps(sp);
+ }
+ else
+ sp->use_bitmaps = 0;
+
+ if (!sp->use_bitmaps) {
+ allocate(sp->rectangles,XRectangle,sp->width*sp->height*sizeof(XRectangle));
+ allocate(sp->lines,XSegment,sp->width*sp->height*sizeof(XSegment));
+ }
+
+ allocate(perm,int,sp->nr_polyominoes*sizeof(int));
+ random_permutation(sp->nr_polyominoes, perm);
+ sp->mono = MI_NPIXELS(mi) < 12;
+ start = NRAND(MI_NPIXELS(mi));
+ for (i=0;i<sp->nr_polyominoes;i++)
+ if (!sp->mono) {
+ sp->polyomino[i].color = MI_PIXEL(mi,(perm[i]*MI_NPIXELS(mi) / sp->nr_polyominoes + start) % MI_NPIXELS(mi));
+ if (sp->rot180) {
+ sp->polyomino[i+1].color = sp->polyomino[i].color;
+ i++;
+ }
+ }
+ else
+ if(sp->use_bitmaps)
+ sp->polyomino[i].color = MI_WHITE_PIXEL(mi);
+ else
+ sp->polyomino[i].color = MI_BLACK_PIXEL(mi);
+ free(perm);
+
+ if (sp->use_bitmaps) {
+ if (sp->mono)
+ sp->border_color = MI_WHITE_PIXEL(mi);
+ else
+ sp->border_color = MI_PIXEL(mi,NRAND(MI_NPIXELS(mi)));
+ }
+
+ sp->x_margin = (MI_WIDTH(mi)-sp->box*sp->width)/2;
+ sp->y_margin = (MI_HEIGHT(mi)-sp->box*sp->height)/2;
+
+ sp->wait = 0;
+
+ /* Clear the background. */
+ MI_CLEARWINDOW(mi);
+
+}
+
+ENTRYPOINT void
+draw_polyominoes (ModeInfo * mi)
+{
+ polyominoesstruct *sp;
+ int poly_no,point_no,transform_index,done,another_attachment_try;
+ point_type attach_point;
+ int i,detach_until;
+
+ if (polyominoeses == NULL)
+ return;
+ sp = &polyominoeses[MI_SCREEN(mi)];
+
+ if (MI_CYCLES(mi) != 0) {
+ if (++sp->counter > MI_CYCLES(mi)) {
+ init_polyominoes(mi);
+ return;
+ }
+ }
+
+ if (sp->box == 0) {
+ init_polyominoes(mi);
+ return;
+ }
+
+ MI_IS_DRAWN(mi) = True;
+ sp->wait--;
+ if (sp->wait>0) return;
+
+ memset(sp->changed_array,0,sp->width*sp->height*sizeof(int));
+
+ poly_no = first_poly_no(sp);
+ point_no = 0;
+ transform_index = 0;
+ done = 0;
+ another_attachment_try = 1;
+ find_blank(sp,&attach_point);
+ if (sp->identical && sp->nr_attached < sp->nr_polyominoes)
+ memset(&REASON_TO_NOT_ATTACH(sp->nr_attached,0),0,sp->nr_polyominoes*sizeof(int));
+ while(!done) {
+ if (sp->nr_attached < sp->nr_polyominoes) {
+ while (!done && another_attachment_try) {
+ done = attach(sp,poly_no,point_no,transform_index,attach_point,0,&REASON_TO_NOT_ATTACH(sp->nr_attached,0));
+ if (done && sp->rot180) {
+ poly_no = first_poly_no(sp);
+ done = attach(sp,poly_no,point_no,transform_index,attach_point,1,&REASON_TO_NOT_ATTACH(sp->nr_attached-1,0));
+ if (!done)
+ detach(sp,&poly_no,&point_no,&transform_index,&attach_point,0);
+ }
+ if (!done)
+ another_attachment_try = next_attach_try(sp,&poly_no,&point_no,&transform_index);
+ }
+ }
+
+ if (sp->identical) {
+ if (!done) {
+ if (sp->nr_attached == 0)
+ done = 1;
+ else {
+ detach_until=sp->nr_attached-1;
+ if (sp->nr_attached < sp->nr_polyominoes)
+ while (detach_until>0 && REASON_TO_NOT_ATTACH(sp->nr_attached,detach_until)==0)
+ detach_until--;
+ while (sp->nr_attached>detach_until) {
+ if (sp->rot180)
+ detach(sp,&poly_no,&point_no,&transform_index,&attach_point,1);
+ detach(sp,&poly_no,&point_no,&transform_index,&attach_point,0);
+ if (sp->nr_attached+1+sp->rot180 < sp->nr_polyominoes)
+ for (i=0;i<sp->nr_polyominoes;i++)
+ REASON_TO_NOT_ATTACH(sp->nr_attached,i) |= REASON_TO_NOT_ATTACH(sp->nr_attached+1+sp->rot180,i);
+ }
+ another_attachment_try = next_attach_try(sp,&poly_no,&point_no,&transform_index);
+ }
+ }
+ }
+ else {
+ if (!done) {
+ if (sp->nr_attached == 0)
+ done = 1;
+ else {
+ if (sp->rot180)
+ detach(sp,&poly_no,&point_no,&transform_index,&attach_point,1);
+ detach(sp,&poly_no,&point_no,&transform_index,&attach_point,0);
+ }
+ another_attachment_try = next_attach_try(sp,&poly_no,&point_no,&transform_index);
+ }
+ }
+ }
+
+ if (sp->use_bitmaps)
+ draw_with_bitmaps(mi,sp);
+ else
+ draw_without_bitmaps(mi,sp);
+
+ if (sp->nr_attached == sp->nr_polyominoes)
+ sp->wait = 100;
+ else
+ sp->wait = 0;
+}
+
+#ifndef STANDALONE
+ENTRYPOINT void
+refresh_polyominoes (ModeInfo * mi)
+{
+ MI_CLEARWINDOW(mi);
+}
+#endif
+
+XSCREENSAVER_MODULE ("Polyominoes", polyominoes)
+
+#endif /* MODE_polyominoes */