1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* polyominoes --- Shows attempts to place polyominoes into a rectangle */
5 static const char sccsid[] = "@(#)polyominoes.c 5.01 2000/12/18 xlockmore";
9 * Copyright (c) 2000 by Stephen Montgomery-Smith <stephen@math.missouri.edu>
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.
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.
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
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)
36 # define MODE_polyominoes
37 #define DEFAULTS "*delay: 10000 \n" \
40 "*fpsSolid: true \n" \
42 # define reshape_polyominoes 0
43 # define polyominoes_handle_event 0
44 # define SMOOTH_COLORS
45 # include "xlockmore.h" /* in xscreensaver distribution */
47 #else /* STANDALONE */
48 # include "xlock.h" /* in xlockmore distribution */
49 #endif /* STANDALONE */
51 #ifdef MODE_polyominoes
52 #define DEF_IDENTICAL "False"
53 #define DEF_PLAIN "False"
55 static Bool identical;
58 static XrmOptionDescRec opts[] =
60 {"-identical", ".polyominoes.identical", XrmoptionNoArg, "on"},
61 {"+identical", ".polyominoes.identical", XrmoptionNoArg, "off"},
62 {"-plain", ".polyominoes.plain", XrmoptionNoArg, "on"},
63 {"+plain", ".polyominoes.plain", XrmoptionNoArg, "off"}
65 static argtype vars[] =
67 {&identical, "identical", "Identical", DEF_IDENTICAL, t_Bool},
68 {&plain, "plain", "Plain", DEF_PLAIN, t_Bool}
70 static OptionStruct desc[] =
72 {"-/+identical", "turn on/off puzzles where the polyomino pieces are identical"},
73 {"-/+plain", "turn on/off plain pieces"}
76 ENTRYPOINT ModeSpecOpt polyominoes_opts =
77 {sizeof opts / sizeof opts[0], opts,
78 sizeof vars / sizeof vars[0], vars, desc};
81 ModStruct polyominoes_description = {
82 "polyominoes", "init_polyominoes", "draw_polyominoes", "release_polyominoes",
83 "refresh_polyominoes", "init_polyominoes", (char *) NULL, &polyominoes_opts,
84 6000, 1, 8192, 1, 64, 1.0, "",
85 "Shows attempts to place polyominoes into a rectangle", 0, NULL
90 /* Each polyomino is described by several quantities:
91 len: the number of squares in the polyomino;
92 point: the list of points;
93 tranform_len: the number of items in transform_list;
94 transform_list: a list of transformations that need to be done in order
95 to get all rotations and reflections (see the function
97 max_white: the maximum number of white squares covered if polyomino
98 is placed on a chess board;
99 color: it's display color;
100 attached: whether it is currently attached to the rectangle;
101 attach_point: point on rectangle where attached;
102 point_no: the number of the point where it is attached;
103 transform_index: which element of transform_list is currently being used.
106 typedef struct {int x,y;} point_type;
108 typedef struct {int len; point_type *point;
109 int transform_len, transform_list[8], max_white;
112 point_type attach_point;
113 int point_no, transform_index;} polyomino_type;
116 typedef struct _polyominoesstruct{
120 unsigned border_color;
123 polyomino_type *polyomino;
125 Bool identical, use3D;
129 /* The array that tells where the polyominoes are attached. */
130 int *array, *changed_array;
132 /* These specify the dimensions of how things appear on the screen. */
133 int box, x_margin, y_margin;
135 /* These booleans decide in which way to try to attach the polyominoes. */
136 int left_right, top_bottom;
138 /* Bitmaps for display purposes. */
140 XImage *bitmaps[256];
142 /* Structures used for display purposes if there is not enough memory
143 to allocate bitmaps (or if the screen is small). */
145 XRectangle *rectangles;
147 /* A procedure that may be used to see if certain configurations
149 int (*check_ok)(struct _polyominoesstruct *sp);
151 /* Tells program that solutions are invariant under 180 degree
155 /* This is a variable used in the case that all the polyominoes are identical
156 that will further prune the search tree. Essentially it will be
157 int reason_to_not_attach[nr_polynominoes][nr_polynominoes];
158 Let me first explain the effect it is trying to overcome. Often
159 in the search process, the computer will first try to fit shapes into
160 a region (call it A), and then into another region (call it B) that is
161 essentially disjoint from A. But it may be that it just is not possible
162 to fit shapes into region B. So it fits something into A, and then
163 tries to fit something into B. Failing it fits something else into A,
164 and then tried again to fit something into B. Thus the program is trying
165 again and again to fit something into B, when it should have figured out
166 the first time that it was impossible.
168 To overcome this, everytime we try to attach a piece, we collect the reasons
169 why it cannot be attached (a boolean for each piece that got in the way).
170 If we see that a piece cannot be attached, we detach the other pieces until
171 we have detached at least one piece for which the boolean reason_to_not_attach
174 int *reason_to_not_attach;
179 eraser_state *eraser;
183 #define ARRAY(x,y) (sp->array[(x)*sp->height+(y)])
184 #define CHANGED_ARRAY(x,y) (sp->changed_array[(x)*sp->height+(y)])
185 #define ARRAY_P(p) (sp->array[(p).x*sp->height+(p).y])
186 #define CHANGED_ARRAY_P(p) (sp->changed_array[(p).x*sp->height+(p).y])
187 #define ARR(x,y) (((x)<0||(x)>=sp->width||(y)<0||(y)>=sp->height)?-2:ARRAY(x,y))
189 #define REASON_TO_NOT_ATTACH(x,y) (sp->reason_to_not_attach[(x)*sp->nr_polyominoes+(y)])
191 #define ROUND8(n) ((((n)+7)/8)*8)
193 /* Defines to index the bitmaps. A set bit indicates that an edge or
194 corner is required. */
199 #define LEFT_UP (1<<4)
200 #define LEFT_DOWN (1<<5)
201 #define RIGHT_UP (1<<6)
202 #define RIGHT_DOWN (1<<7)
203 #define IS_LEFT(n) ((n) & LEFT)
204 #define IS_RIGHT(n) ((n) & RIGHT)
205 #define IS_UP(n) ((n) & UP)
206 #define IS_DOWN(n) ((n) & DOWN)
207 #define IS_LEFT_UP(n) ((n) & LEFT_UP)
208 #define IS_LEFT_DOWN(n) ((n) & LEFT_DOWN)
209 #define IS_RIGHT_UP(n) ((n) & RIGHT_UP)
210 #define IS_RIGHT_DOWN(n) ((n) & RIGHT_DOWN)
212 /* Defines to access the bitmaps. */
213 #define BITNO(x,y) ((x)+(y)*ROUND8(sp->box))
214 #define SETBIT(n,x,y) {data[BITNO(x,y)/8] |= 1<<(BITNO(x,y)%8);}
215 #define RESBIT(n,x,y) {data[BITNO(x,y)/8] &= ~(1<<(BITNO(x,y)%8));}
216 #define TWOTHIRDSBIT(n,x,y) {if ((x+y-1)%3) SETBIT(n,x,y) else RESBIT(n,x,y)}
217 #define HALFBIT(n,x,y) {if ((x-y)%2) SETBIT(n,x,y) else RESBIT(n,x,y)}
218 #define THIRDBIT(n,x,y) {if (!((x-y-1)%3)) SETBIT(n,x,y) else RESBIT(n,x,y)}
219 #define THREEQUARTERSBIT(n,x,y) \
220 {if ((y%2)||((x+2+y/2+1)%2)) SETBIT(n,x,y) else RESBIT(n,x,y)}
221 #define NOTHALFBIT(n,x,y) {if ((x-y)%2) RESBIT(n,x,y) else SETBIT(n,x,y)}
223 /* Parameters for bitmaps. */
224 #define G ((sp->box/45)+1) /* 1/2 of gap between polyominoes. */
225 #define T ((sp->box<=12)?1:(G*2)) /* Thickness of walls of polyominoes. */
226 #define R ((sp->box<=12)?1:(G*6)) /* Amount of rounding. */
227 #define RT ((sp->box<=12)?1:(G*3)) /* Thickness of wall of rounded parts.
228 Here 3 is an approximation to 2 sqrt(2). */
229 #define RR 0 /* Roof ridge thickness */
232 /* A list of those bitmaps we need to create to display any pentomino. */
233 /* (not used right now because it does not seem to work for hexonimoes.) */
235 static int bitmaps_needed[] =
237 LEFT_UP|LEFT_DOWN|RIGHT_UP|RIGHT_DOWN,
239 LEFT|RIGHT_UP|RIGHT_DOWN,
240 RIGHT|LEFT_UP|LEFT_DOWN,
241 UP|LEFT_DOWN|RIGHT_DOWN,
242 DOWN|LEFT_UP|RIGHT_UP,
252 /* These needed for hexonimoes*/
257 LEFT_DOWN|RIGHT_UP|RIGHT_DOWN,
258 LEFT_UP|RIGHT_UP|RIGHT_DOWN,
259 LEFT_UP|LEFT_DOWN|RIGHT_DOWN,
260 LEFT_UP|LEFT_DOWN|RIGHT_UP,
282 static int bitmap_needed(int n)
286 for (i=0;bitmaps_needed[i]!=-1;i++)
287 if (n == bitmaps_needed[i])
294 /* Some debugging routines.
296 static void print_board(polyominoesstruct *sp)
299 for (y=0;y<sp->height;y++) {
300 for (x=0;x<sp->width;x++)
301 if (ARRAY(x,y) == -1)
304 fprintf(stderr,"%c",'a'+ARRAY(x,y));
305 fprintf(stderr,"\n");
307 fprintf(stderr,"\n");
310 static void print_points(point_type *point, int len)
315 fprintf(stderr,"(%d %d) ",point[i].x,point[i].y);
318 static void print_polyomino(polyomino_type poly)
322 print_points(poly.point,poly.len);
323 fprintf(stderr,"\n");
324 for (i=0;i<poly.transform_len;i++)
325 fprintf(stderr,"%d ",poly.transform_list[i]);
326 fprintf(stderr,"\n");
330 static polyominoesstruct *polyominoeses = (polyominoesstruct *) NULL;
333 void random_permutation(int n, int a[])
337 for (i=0;i<n;i++) a[i] = -1;
351 /************************************************************
352 These are the routines for manipulating the polyominoes and
353 attaching and detaching them from the rectangle.
354 ************************************************************/
356 static void transform(point_type in, point_type offset, int transform_no,
357 point_type attach_point, point_type *out) {
358 switch (transform_no) {
359 case 0: out->x=in.x-offset.x+attach_point.x;
360 out->y=in.y-offset.y+attach_point.y;
362 case 1: out->x=-(in.y-offset.y)+attach_point.x;
363 out->y=in.x-offset.x+attach_point.y;
365 case 2: out->x=-(in.x-offset.x)+attach_point.x;
366 out->y=-(in.y-offset.y)+attach_point.y;
368 case 3: out->x=in.y-offset.y+attach_point.x;
369 out->y=-(in.x-offset.x)+attach_point.y;
371 case 4: out->x=-(in.x-offset.x)+attach_point.x;
372 out->y=in.y-offset.y+attach_point.y;
374 case 5: out->x=in.y-offset.y+attach_point.x;
375 out->y=in.x-offset.x+attach_point.y;
377 case 6: out->x=in.x-offset.x+attach_point.x;
378 out->y=-(in.y-offset.y)+attach_point.y;
380 case 7: out->x=-(in.y-offset.y)+attach_point.x;
381 out->y=-(in.x-offset.x)+attach_point.y;
386 static int first_poly_no(polyominoesstruct *sp)
391 while(poly_no<sp->nr_polyominoes && sp->polyomino[poly_no].attached)
396 static void next_poly_no(polyominoesstruct *sp, int *poly_no)
400 *poly_no = sp->nr_polyominoes;
404 } while (*poly_no<sp->nr_polyominoes && sp->polyomino[*poly_no].attached);
408 /* check_all_regions_multiple_of looks for connected regions of
409 blank spaces, and returns 0 if it finds a connected region containing
410 a number of blanks that is not a multiple of n.
413 static void count_adjacent_blanks(polyominoesstruct *sp, int *count, int x, int y, int blank_mark)
416 if (ARRAY(x,y) == -1) {
418 ARRAY(x,y) = blank_mark;
419 if (x>=1) count_adjacent_blanks(sp, count,x-1,y,blank_mark);
420 if (x<sp->width-1) count_adjacent_blanks(sp, count,x+1,y,blank_mark);
421 if (y>=1) count_adjacent_blanks(sp, count,x,y-1,blank_mark);
422 if (y<sp->height-1) count_adjacent_blanks(sp, count,x,y+1,blank_mark);
426 static int check_all_regions_multiple_of(polyominoesstruct *sp, int n)
428 int x,y,count,good = 1;
430 for (x=0;x<sp->width && good;x++) for (y=0;y<sp->height && good;y++) {
432 count_adjacent_blanks(sp, &count,x,y,-2);
436 for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++)
437 if (ARRAY(x,y) == -2)
443 static int check_all_regions_positive_combination_of(polyominoesstruct *sp, int m, int n)
445 int x,y,count,good = 1;
447 for (x=0;x<sp->width && good;x++) for (y=0;y<sp->height && good;y++) {
449 count_adjacent_blanks(sp, &count,x,y,-2);
451 for (;count>=0 && !good;count-=m)
455 for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++)
456 if (ARRAY(x,y) == -2)
462 static int find_smallest_blank_component(polyominoesstruct *sp)
464 int x,y,size,smallest_size,blank_mark,smallest_mark;
466 smallest_mark = blank_mark = -10;
467 smallest_size = 1000000000;
468 for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) if (ARRAY(x,y) == -1) {
470 count_adjacent_blanks(sp, &size,x,y,blank_mark);
471 if (size<smallest_size) {
472 smallest_mark = blank_mark;
473 smallest_size = size;
478 return smallest_mark;
481 /* "Chess board" check - see init_max_whites_list above for more details.
483 /* If the rectangle is alternatively covered by white and black
484 squares (chess board style), then this gives the list of
485 the maximal possible whites covered by each polyomino. It
486 is used by the function whites_ok which makes sure that the
487 array has a valid number of white or black remaining blanks left.
490 static int whites_ok(polyominoesstruct *sp)
492 int x,y,poly_no,whites=0,blacks=0,max_white=0,min_white=0;
494 for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) {
495 if (ARRAY(x,y) == -1 && (x+y)%2) whites++;
496 if (ARRAY(x,y) == -1 && (x+y+1)%2) blacks++;
498 for (poly_no=0;poly_no<sp->nr_polyominoes;poly_no++) if (!sp->polyomino[poly_no].attached) {
499 max_white += sp->polyomino[poly_no].max_white;
500 min_white += sp->polyomino[poly_no].len - sp->polyomino[poly_no].max_white;
502 return (min_white <= blacks && min_white <= whites
503 && blacks <= max_white && whites <= max_white);
506 /* This routine looks at the point (x,y) and sees how many polyominoes
507 and all their various transforms may be attached there.
511 score_point(polyominoesstruct *sp, int x, int y, int min_score_so_far)
513 int poly_no, point_no, transform_index, i, attachable;
514 point_type attach_point, target_point;
517 if (x>=1 && x<sp->width-1 && y>=1 && y<sp->height-1 &&
518 ARRAY(x-1,y-1)<0 && ARRAY(x-1,y)<0 && ARRAY(x-1,y+1)<0 &&
519 ARRAY(x+1,y-1)<0 && ARRAY(x+1,y)<0 && ARRAY(x+1,y+1)<0 &&
520 ARRAY(x,y-1)<0 && ARRAY(x,y+1)<0)
525 for (poly_no=first_poly_no(sp);poly_no<sp->nr_polyominoes;next_poly_no(sp,&poly_no))
526 if (!sp->polyomino[poly_no].attached) {
527 for (point_no=0;point_no<sp->polyomino[poly_no].len;point_no++)
528 for (transform_index=0;transform_index<sp->polyomino[poly_no].transform_len;transform_index++) {
530 for (i=0;i<sp->polyomino[poly_no].len;i++) {
531 transform(sp->polyomino[poly_no].point[i],
532 sp->polyomino[poly_no].point[point_no],
533 sp->polyomino[poly_no].transform_list[transform_index],
534 attach_point, &target_point);
535 if ( ! ((target_point.x>=0) && (target_point.x<sp->width)
536 && (target_point.y>=0) && (target_point.y<sp->height)
537 && (ARRAY_P(target_point)<0))) {
544 if (score>=min_score_so_far)
553 static void find_blank(polyominoesstruct *sp, point_type *point)
555 int score, worst_score;
559 blank_mark = find_smallest_blank_component(sp);
561 worst_score = 1000000;
562 for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) if (ARRAY(x,y)==blank_mark) {
563 score = 100*score_point(sp,x,y,worst_score);
565 if (sp->left_right) score += 10*x;
566 else score += 10*(sp->width-1-x);
567 if (sp->top_bottom) score += y;
568 else score += (sp->height-1-y);
570 if (score<worst_score) {
577 for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++)
578 if (ARRAY(x,y)<0) ARRAY(x,y) = -1;
581 /* Detaches the most recently attached polyomino. */
584 void detach(polyominoesstruct *sp, int *poly_no, int *point_no, int *transform_index, point_type *attach_point, int rot180)
587 point_type target_point;
589 if (sp->nr_attached == 0) return;
591 *poly_no = sp->attach_list[sp->nr_attached];
592 *point_no = sp->polyomino[*poly_no].point_no;
593 *transform_index = sp->polyomino[*poly_no].transform_index;
594 *attach_point = sp->polyomino[*poly_no].attach_point;
595 for (i=0;i<sp->polyomino[*poly_no].len;i++) {
596 transform(sp->polyomino[*poly_no].point[i],
597 sp->polyomino[*poly_no].point[*point_no],
598 sp->polyomino[*poly_no].transform_list[*transform_index]^(rot180<<1),
599 *attach_point, &target_point);
600 ARRAY_P(target_point) = -1;
601 CHANGED_ARRAY_P(target_point) = 1;
604 sp->polyomino[*poly_no].attached = 0;
607 /* Attempts to attach a polyomino at point (x,y) at the
608 point_no-th point of that polyomino, using the transform
609 transform_no. Returns 1 if successful.
613 int attach(polyominoesstruct *sp, int poly_no, int point_no, int transform_index, point_type attach_point, int rot180,
614 int *reason_to_not_attach) {
615 point_type target_point;
617 int attachable = 1, worst_reason_not_to_attach = 1000000000;
620 attach_point.x = sp->width-1-attach_point.x;
621 attach_point.y = sp->height-1-attach_point.y;
624 if (sp->polyomino[poly_no].attached)
627 for (i=0;i<sp->polyomino[poly_no].len;i++) {
628 transform(sp->polyomino[poly_no].point[i],
629 sp->polyomino[poly_no].point[point_no],
630 sp->polyomino[poly_no].transform_list[transform_index]^(rot180<<1),
631 attach_point, &target_point);
632 if ( ! ((target_point.x>=0) && (target_point.x<sp->width)
633 && (target_point.y>=0) && (target_point.y<sp->height)
634 && (ARRAY_P(target_point) == -1))) {
637 if ((target_point.x>=0) && (target_point.x<sp->width)
638 && (target_point.y>=0) && (target_point.y<sp->height)
639 && (ARRAY_P(target_point) >= 0)
640 && (ARRAY_P(target_point)<worst_reason_not_to_attach))
641 worst_reason_not_to_attach = ARRAY_P(target_point);
648 if (sp->identical && !attachable) {
649 if (worst_reason_not_to_attach < 1000000000)
650 reason_to_not_attach[worst_reason_not_to_attach] = 1;
654 for (i=0;i<sp->polyomino[poly_no].len;i++) {
655 transform(sp->polyomino[poly_no].point[i],
656 sp->polyomino[poly_no].point[point_no],
657 sp->polyomino[poly_no].transform_list[transform_index]^(rot180<<1),
658 attach_point, &target_point);
659 ARRAY_P(target_point) = poly_no;
660 CHANGED_ARRAY_P(target_point) = 1;
663 sp->attach_list[sp->nr_attached] = poly_no;
666 sp->polyomino[poly_no].attached = 1;
667 sp->polyomino[poly_no].point_no = point_no;
668 sp->polyomino[poly_no].attach_point = attach_point;
669 sp->polyomino[poly_no].transform_index = transform_index;
671 if (!sp->check_ok(sp)) {
672 detach(sp,&poly_no,&point_no,&transform_index,&attach_point,rot180);
680 int next_attach_try(polyominoesstruct *sp, int *poly_no, int *point_no, int *transform_index)
683 (*transform_index)++;
684 if (*transform_index>=sp->polyomino[*poly_no].transform_len) {
685 *transform_index = 0;
687 if (*point_no>=sp->polyomino[*poly_no].len) {
689 next_poly_no(sp,poly_no);
690 if (*poly_no>=sp->nr_polyominoes) {
691 *poly_no = first_poly_no(sp);
700 /*******************************************************
702 *******************************************************/
705 draw_without_bitmaps(ModeInfo * mi, polyominoesstruct *sp)
707 Display *display = MI_DISPLAY(mi);
708 Window window = MI_WINDOW(mi);
710 int x,y,poly_no,nr_lines,nr_rectangles;
712 XSetLineAttributes(display,gc,sp->box/10+1,LineSolid,CapRound,JoinRound);
714 for (poly_no=-1;poly_no<sp->nr_polyominoes;poly_no++) {
716 for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++)
717 if (CHANGED_ARRAY(x,y) && ARRAY(x,y) == poly_no) {
718 sp->rectangles[nr_rectangles].x = sp->x_margin + sp->box*x;
719 sp->rectangles[nr_rectangles].y = sp->y_margin + sp->box*y;
720 sp->rectangles[nr_rectangles].width = sp->box;
721 sp->rectangles[nr_rectangles].height = sp->box;
725 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
727 XSetForeground(display, gc, sp->polyomino[poly_no].color);
728 XFillRectangles(display, window, gc, sp->rectangles, nr_rectangles);
731 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
734 for (x=0;x<sp->width-1;x++) for (y=0;y<sp->height;y++) {
735 if (ARRAY(x,y) == -1 && ARRAY(x+1,y) == -1
736 && (CHANGED_ARRAY(x,y) || CHANGED_ARRAY(x+1,y))) {
737 sp->lines[nr_lines].x1 = sp->x_margin + sp->box*(x+1);
738 sp->lines[nr_lines].y1 = sp->y_margin + sp->box*y;
739 sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1);
740 sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1);
744 XDrawSegments(display, window, gc, sp->lines, nr_lines);
747 for (x=0;x<sp->width;x++) for (y=0;y<sp->height-1;y++) {
748 if (ARRAY(x,y) == -1 && ARRAY(x,y+1) == -1
749 && (CHANGED_ARRAY(x,y) || CHANGED_ARRAY(x,y+1))) {
750 sp->lines[nr_lines].x1 = sp->x_margin + sp->box*x;
751 sp->lines[nr_lines].y1 = sp->y_margin + sp->box*(y+1);
752 sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1);
753 sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1);
757 XDrawSegments(display, window, gc, sp->lines, nr_lines);
759 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
760 XDrawRectangle(display, window, gc, sp->x_margin, sp->y_margin, sp->box*sp->width, sp->box*sp->height);
762 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
765 for (x=0;x<sp->width-1;x++) for (y=0;y<sp->height;y++) {
766 if (ARRAY(x+1,y) != ARRAY(x,y)) {
767 sp->lines[nr_lines].x1 = sp->x_margin + sp->box*(x+1);
768 sp->lines[nr_lines].y1 = sp->y_margin + sp->box*y;
769 sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1);
770 sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1);
774 XDrawSegments(display, window, gc, sp->lines, nr_lines);
777 for (x=0;x<sp->width;x++) for (y=0;y<sp->height-1;y++) {
778 if (ARRAY(x,y+1) != ARRAY(x,y)) {
779 sp->lines[nr_lines].x1 = sp->x_margin + sp->box*x;
780 sp->lines[nr_lines].y1 = sp->y_margin + sp->box*(y+1);
781 sp->lines[nr_lines].x2 = sp->x_margin + sp->box*(x+1);
782 sp->lines[nr_lines].y2 = sp->y_margin + sp->box*(y+1);
786 XDrawSegments(display, window, gc, sp->lines, nr_lines);
787 XSetLineAttributes(display,gc,1,LineSolid,CapRound,JoinRound);
790 static void create_bitmaps(ModeInfo * mi, polyominoesstruct *sp)
795 for (n=0;n<256;n++) {
797 /* Avoid duplication of identical bitmaps. */
798 if (IS_LEFT_UP(n) && (IS_LEFT(n) || IS_UP(n)))
799 sp->bitmaps[n] = sp->bitmaps[n & ~LEFT_UP];
800 else if (IS_LEFT_DOWN(n) && (IS_LEFT(n) || IS_DOWN(n)))
801 sp->bitmaps[n] = sp->bitmaps[n & ~LEFT_DOWN];
802 else if (IS_RIGHT_UP(n) && (IS_RIGHT(n) || IS_UP(n)))
803 sp->bitmaps[n] = sp->bitmaps[n & ~RIGHT_UP];
804 else if (IS_RIGHT_DOWN(n) && (IS_RIGHT(n) || IS_DOWN(n)))
805 sp->bitmaps[n] = sp->bitmaps[n & ~RIGHT_DOWN];
807 else /* if (bitmap_needed(n)) */ {
808 data = (char *) malloc(sizeof(char)*(sp->box*ROUND8(sp->box)/8));
814 for (y=0;y<sp->box;y++) for (x=0;x<sp->box;x++) {
816 #ifdef SMALL_BELLYBUTTON
817 if (x >= sp->box / 2 && x <= sp->box / 2 + 1 &&
818 y >= sp->box / 2 && y <= sp->box / 2 + 1)
823 } else if ((x>=y && x<=sp->box-y-1 && IS_UP(n))
824 || (x<=y && x<=sp->box-y-1 && y<sp->box/2 && !IS_LEFT(n))
825 || (x>=y && x>=sp->box-y-1 && y<sp->box/2 && !IS_RIGHT(n)))
827 else if ((x<=y && x<=sp->box-y-1 && IS_LEFT(n))
828 || (x>=y && x<=sp->box-y-1 && x<sp->box/2 && !IS_UP(n))
829 || (x<=y && x>=sp->box-y-1 && x<sp->box/2 && !IS_DOWN(n)))
831 else if ((x>=y && x>=sp->box-y-1 && IS_RIGHT(n))
832 || (x>=y && x<=sp->box-y-1 && x>=sp->box/2 && !IS_UP(n))
833 || (x<=y && x>=sp->box-y-1 && x>=sp->box/2 && !IS_DOWN(n)))
835 else if ((x<=y && x>=sp->box-y-1 && IS_DOWN(n))
836 || (x<=y && x<=sp->box-y-1 && y>=sp->box/2 && !IS_LEFT(n))
837 || (x>=y && x>=sp->box-y-1 && y>=sp->box/2 && !IS_RIGHT(n)))
842 for (y=0;y<sp->box;y++) for (x=G;x<G+T;x++)
845 for (y=0;y<sp->box;y++) for (x=G;x<G+T;x++)
846 SETBIT(n,sp->box-1-x,y)
848 for (x=0;x<sp->box;x++) for (y=G;y<G+T;y++)
851 for (x=0;x<sp->box;x++) for (y=G;y<G+T;y++)
852 SETBIT(n,x,sp->box-1-y)
854 for (y=0;y<sp->box;y++) for (x=0;x<G;x++)
857 for (y=0;y<sp->box;y++) for (x=0;x<G;x++)
858 RESBIT(n,sp->box-1-x,y)
860 for (x=0;x<sp->box;x++) for (y=0;y<G;y++)
863 for (x=0;x<sp->box;x++) for (y=0;y<G;y++)
864 RESBIT(n,x,sp->box-1-y)
866 if (IS_LEFT(n) && IS_UP(n))
868 for (y=G;y<=R+2*G-x;y++) {
874 if (IS_LEFT(n) && IS_DOWN(n))
876 for (y=G;y<=R+2*G-x;y++) {
878 SETBIT(n,x,sp->box-1-y)
880 RESBIT(n,x,sp->box-1-y)
882 if (IS_RIGHT(n) && IS_UP(n))
884 for (y=G;y<=R+2*G-x;y++) {
886 SETBIT(n,sp->box-1-x,y)
888 RESBIT(n,sp->box-1-x,y)
890 if (IS_RIGHT(n) && IS_DOWN(n))
892 for (y=G;y<=R+2*G-x;y++) {
894 SETBIT(n,sp->box-1-x,sp->box-1-y)
896 RESBIT(n,sp->box-1-x,sp->box-1-y)
899 if (!IS_LEFT(n) && !IS_UP(n) && IS_LEFT_UP(n)) {
900 for (x=0;x<G;x++) for(y=0;y<G;y++)
902 for (x=G;x<G+T;x++) for(y=0;y<G;y++)
904 for (x=0;x<G+T;x++) for(y=G;y<G+T;y++)
907 if (!IS_LEFT(n) && !IS_DOWN(n) && IS_LEFT_DOWN(n)) {
908 for (x=0;x<G;x++) for(y=0;y<G;y++)
909 RESBIT(n,x,sp->box-1-y)
910 for (x=G;x<G+T;x++) for(y=0;y<G;y++)
911 SETBIT(n,x,sp->box-1-y)
912 for (x=0;x<G+T;x++) for(y=G;y<G+T;y++)
913 SETBIT(n,x,sp->box-1-y)
915 if (!IS_RIGHT(n) && !IS_UP(n) && IS_RIGHT_UP(n)) {
916 for (x=0;x<G;x++) for(y=0;y<G;y++)
917 RESBIT(n,sp->box-1-x,y)
918 for (x=G;x<G+T;x++) for(y=0;y<G;y++)
919 SETBIT(n,sp->box-1-x,y)
920 for (x=0;x<G+T;x++) for(y=G;y<G+T;y++)
921 SETBIT(n,sp->box-1-x,y)
923 if (!IS_RIGHT(n) && !IS_DOWN(n) && IS_RIGHT_DOWN(n)) {
924 for (x=0;x<G;x++) for(y=0;y<G;y++)
925 RESBIT(n,sp->box-1-x,sp->box-1-y)
926 for (x=G;x<G+T;x++) for(y=0;y<G;y++)
927 SETBIT(n,sp->box-1-x,sp->box-1-y)
928 for (x=0;x<G+T;x++) for(y=G;y<G+T;y++)
929 SETBIT(n,sp->box-1-x,sp->box-1-y)
932 #ifdef LARGE_BELLYBUTTON
934 if (!IS_LEFT(n) && !IS_UP(n) && !IS_LEFT_UP(n))
935 for (x=0;x<G+T;x++) for(y=0;y<G+T;y++)
937 if (!IS_LEFT(n) && !IS_DOWN(n) && !IS_LEFT_DOWN(n))
938 for (x=0;x<G+T;x++) for(y=sp->box-G-T;y<sp->box;y++)
940 if (!IS_RIGHT(n) && !IS_UP(n) && !IS_RIGHT_UP(n))
941 for (x=sp->box-G-T;x<sp->box;x++) for(y=0;y<G+T;y++)
943 if (!IS_RIGHT(n) && !IS_DOWN(n) && !IS_RIGHT_DOWN(n))
944 for (x=sp->box-G-T;x<sp->box;x++) for(y=sp->box-G-T;y<sp->box;y++)
951 if (!IS_LEFT(n) && !IS_UP(n) && !IS_LEFT_UP(n))
952 for (x=0;x<sp->box/2-RR;x++) for(y=0;y<sp->box/2-RR;y++)
953 THREEQUARTERSBIT(n,x,y)
954 if (!IS_LEFT(n) && !IS_DOWN(n) && !IS_LEFT_DOWN(n))
955 for (x=0;x<sp->box/2-RR;x++) for(y=sp->box/2+RR;y<sp->box;y++)
956 THREEQUARTERSBIT(n,x,y)
957 if (!IS_RIGHT(n) && !IS_UP(n) && !IS_RIGHT_UP(n))
958 for (x=sp->box/2+RR;x<sp->box;x++) for(y=0;y<sp->box/2-RR;y++)
959 THREEQUARTERSBIT(n,x,y)
960 if (!IS_RIGHT(n) && !IS_DOWN(n) && !IS_RIGHT_DOWN(n))
961 for (x=sp->box/2+RR;x<sp->box;x++) for(y=sp->box/2+RR;y<sp->box;y++)
962 THREEQUARTERSBIT(n,x,y)
965 sp->bitmaps[n] = XCreateImage(MI_DISPLAY(mi), MI_VISUAL(mi), 1, XYBitmap,
966 0, data, sp->box, sp->box, 8, 0);
967 if (sp->bitmaps[n] == None) {
972 sp->bitmaps[n]->byte_order = MSBFirst;
973 sp->bitmaps[n]->bitmap_unit = 8;
974 sp->bitmaps[n]->bitmap_bit_order = LSBFirst;
981 static void draw_with_bitmaps(ModeInfo * mi, polyominoesstruct *sp)
983 Display *display = MI_DISPLAY(mi);
984 Window window = MI_WINDOW(mi);
986 int x,y,t,bitmap_index;
988 for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) {
989 if (ARRAY(x,y) == -1) {
990 if (CHANGED_ARRAY(x,y)) {
991 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
992 XFillRectangle(display,window,gc,
993 sp->x_margin + sp->box*x,
994 sp->y_margin + sp->box*y,
999 XSetForeground(display, gc, sp->polyomino[ARRAY(x,y)].color);
1001 if (ARR(x,y) != ARR(x-1,y)) bitmap_index |= LEFT;
1002 if (ARR(x,y) != ARR(x+1,y)) bitmap_index |= RIGHT;
1003 if (ARR(x,y) != ARR(x,y-1)) bitmap_index |= UP;
1004 if (ARR(x,y) != ARR(x,y+1)) bitmap_index |= DOWN;
1005 if (ARR(x,y) != ARR(x-1,y-1)) bitmap_index |= LEFT_UP;
1006 if (ARR(x,y) != ARR(x-1,y+1)) bitmap_index |= LEFT_DOWN;
1007 if (ARR(x,y) != ARR(x+1,y-1)) bitmap_index |= RIGHT_UP;
1008 if (ARR(x,y) != ARR(x+1,y+1)) bitmap_index |= RIGHT_DOWN;
1009 (void) XPutImage(display,window,gc,
1010 sp->bitmaps[bitmap_index],
1012 sp->x_margin + sp->box*x,
1013 sp->y_margin + sp->box*y,
1018 XSetForeground(display, gc, sp->border_color);
1020 XDrawRectangle(display,window,gc,
1021 sp->x_margin-t-1,sp->y_margin-t-1,
1022 sp->box*sp->width+1+2*t, sp->box*sp->height+1+2*t);
1026 /***************************************************
1027 Routines to initialise and close down polyominoes.
1028 ***************************************************/
1030 static void free_bitmaps(polyominoesstruct *sp)
1035 /* Don't bother to free duplicates */
1036 if (IS_LEFT_UP(n) && (IS_LEFT(n) || IS_UP(n)))
1037 sp->bitmaps[n] = None;
1038 else if (IS_LEFT_DOWN(n) && (IS_LEFT(n) || IS_DOWN(n)))
1039 sp->bitmaps[n] = None;
1040 else if (IS_RIGHT_UP(n) && (IS_RIGHT(n) || IS_UP(n)))
1041 sp->bitmaps[n] = None;
1042 else if (IS_RIGHT_DOWN(n) && (IS_RIGHT(n) || IS_DOWN(n)))
1043 sp->bitmaps[n] = None;
1045 else if (sp->bitmaps[n] != None) {
1046 XDestroyImage(sp->bitmaps[n]);
1047 sp->bitmaps[n] = None;
1051 #define deallocate(p,t) if ((p)!=NULL) {free(p); p=(t*)NULL;}
1053 static void free_polyominoes(polyominoesstruct *sp)
1057 for (n=0;n<sp->nr_polyominoes;n++) {
1058 deallocate(sp->polyomino[n].point, point_type);
1061 deallocate(sp->polyomino, polyomino_type);
1062 deallocate(sp->attach_list, int);
1063 deallocate(sp->rectangles, XRectangle);
1064 deallocate(sp->lines, XSegment);
1065 deallocate(sp->reason_to_not_attach, int);
1066 deallocate(sp->array, int);
1067 deallocate(sp->changed_array, int);
1072 #define set_allocate(p,type,size) p = (type *) malloc(size); \
1073 if ((p)==NULL) {free_polyominoes(sp);return 0;}
1075 #define copy_polyomino(dst,src,new_rand) \
1076 (dst).len=(src).len; \
1077 (dst).max_white = (src).max_white; \
1078 set_allocate((dst).point,point_type,sizeof(point_type)*(src).len); \
1079 (dst).len = (src).len; \
1081 random_permutation((src).len,perm_point); \
1082 for (i=0;i<(src).len;i++) \
1083 (dst).point[i] = (src).point[perm_point[i]]; \
1084 (dst).transform_len = (src).transform_len; \
1086 random_permutation((src).transform_len,perm_transform); \
1087 for (i=0;i<(src).transform_len;i++) \
1088 (dst).transform_list[i] = (src).transform_list[perm_transform[i]]; \
1092 /***************************************************
1093 Puzzle specific initialization routines.
1094 ***************************************************/
1097 int check_pentomino_puzzle(polyominoesstruct *sp)
1099 return check_all_regions_multiple_of(sp, 5) && whites_ok(sp);
1103 int check_hexomino_puzzle(polyominoesstruct *sp)
1105 return check_all_regions_multiple_of(sp, 6) && whites_ok(sp);
1109 int check_tetr_pentomino_puzzle(polyominoesstruct *sp)
1111 return check_all_regions_positive_combination_of(sp, 5, 4) && whites_ok(sp);
1115 int check_pent_hexomino_puzzle(polyominoesstruct *sp)
1117 return check_all_regions_positive_combination_of(sp, 6, 5) && whites_ok(sp);
1121 int check_heptomino_puzzle(polyominoesstruct *sp)
1123 return check_all_regions_multiple_of(sp, 7) && whites_ok(sp);
1127 int check_octomino_puzzle(polyominoesstruct *sp)
1129 return check_all_regions_multiple_of(sp, 8) && whites_ok(sp);
1133 int check_dekomino_puzzle(polyominoesstruct *sp)
1135 return check_all_regions_multiple_of(sp, 10) && whites_ok(sp);
1139 int check_elevenomino_puzzle(polyominoesstruct *sp)
1141 return check_all_regions_multiple_of(sp, 11) && whites_ok(sp);
1144 static struct {int len; point_type point[4];
1145 int transform_len, transform_list[8], max_white;} tetromino[5] =
1150 {4, {{0,0}, {1,0}, {2,0}, {3,0}},
1151 2, {0, 1, -1, -1, -1, -1, -1, -1}, 2},
1156 {4, {{0,0}, {1,0}, {2,0}, {2,1}},
1157 8, {0, 1, 2, 3, 4, 5, 6, 7}, 2},
1162 {4, {{0,0}, {1,0}, {1,1}, {2,0}},
1163 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1168 {4, {{0,0}, {1,0}, {1,1}, {2,1}},
1169 4, {0, 1, 4, 5, -1, -1, -1, -1}, 2},
1174 {4, {{0,0}, {0,1}, {1,0}, {1,1}},
1175 1, {0, -1, -1, -1, -1, -1, -1, -1}, 2}};
1178 static struct pentomino_struct {int len; point_type point[5];
1179 int transform_len, transform_list[8], max_white;}
1185 {5, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}},
1186 2, {0, 1, -1, -1, -1, -1, -1, -1}, 3},
1191 {5, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}},
1192 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1197 {5, {{0,0}, {1,0}, {2,0}, {2,1}, {3,0}},
1198 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1204 {5, {{0,0}, {1,0}, {2,-1}, {2,0}, {2,1}},
1205 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1210 {5, {{0,0}, {1,0}, {2,0}, {2,1}, {3,1}},
1211 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1216 {5, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}},
1217 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1223 {5, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}},
1224 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1230 {5, {{0,0}, {1,-1}, {1,0}, {2,0}, {2,1}},
1231 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1236 {5, {{0,0}, {0,1}, {1,0}, {2,0}, {2,1}},
1237 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1243 {5, {{0,0}, {0,1}, {1,0}, {2,-1}, {2,0}},
1244 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3},
1250 {5, {{0,0}, {1,-1}, {1,0}, {1,1}, {2,0}},
1251 1, {0, -1, -1, -1, -1, -1, -1, -1}, 4},
1257 {5, {{0,0}, {1,0}, {1,1}, {2,1}, {2,2}},
1258 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3}};
1261 static struct hexomino_struct {int len; point_type point[6];
1262 int transform_len, transform_list[8], max_white;}
1268 {6, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {5,0}},
1269 2, {0, 1, -1, -1, -1, -1, -1, -1}, 3},
1274 {6, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {4,1}},
1275 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1280 {6, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}, {4,0}},
1281 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
1286 {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,0}, {4,0}},
1287 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1293 {6, {{0,0}, {1,0}, {2,0}, {3,-1}, {3,0}, {3,1}},
1294 4, {0, 1, 2, 3, -1, -1, -1, -1}, 4},
1299 {6, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}, {4,1}},
1300 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1305 {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,0}, {3,1}},
1306 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1312 {6, {{0,0}, {1,0}, {2,0}, {3,0}, {3,1}, {3,2}},
1313 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1319 {6, {{0,0}, {1,0}, {2,-1}, {2,0}, {3,0}, {3,1}},
1320 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1325 {6, {{0,0}, {1,0}, {1,1}, {2,0}, {3,0}, {3,1}},
1326 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
1332 {6, {{0,0}, {1,-1}, {1,0}, {2,0}, {3,0}, {3,1}},
1333 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
1338 {6, {{0,0}, {0,1}, {1,0}, {2,0}, {3,0}, {3,1}},
1339 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1345 {6, {{0,0}, {0,1}, {1,0}, {2,0}, {3,-1}, {3,0}},
1346 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3},
1352 {6, {{0,0}, {1,0}, {2,-1}, {2,0}, {2,1}, {3,0}},
1353 4, {0, 1, 2, 3, -1, -1, -1, -1}, 4},
1358 {6, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}, {3,0}},
1359 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1365 {6, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}, {3,0}},
1366 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1372 {6, {{0,0}, {1,-1}, {1,0}, {2,0}, {2,1}, {3,0}},
1373 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3},
1379 {6, {{0,0}, {1,0}, {2,-1}, {2,0}, {2,1}, {3,-1}},
1380 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1386 {6, {{0,0}, {1,-1}, {1,0}, {2,-1}, {2,0}, {2,1}},
1387 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1393 {6, {{0,0}, {0,1}, {1,0}, {2,-1}, {2,0}, {2,1}},
1394 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
1399 {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,1}, {4,1}},
1400 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3},
1406 {6, {{0,0}, {1,0}, {2,0}, {2,1}, {3,1}, {3,2}},
1407 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1412 {6, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}, {3,1}},
1413 4, {0, 1, 4, 5, -1, -1, -1, -1}, 4},
1419 {6, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}, {3,1}},
1420 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
1426 {6, {{0,0}, {1,-1}, {1,0}, {2,0}, {2,1}, {3,1}},
1427 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4},
1432 {6, {{0,0}, {0,1}, {1,0}, {2,0}, {2,1}, {3,1}},
1433 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1439 {6, {{0,0}, {1,0}, {1,1}, {2,0}, {2,1}, {2,2}},
1440 4, {0, 1, 2, 3, -1, -1, -1, -1}, 4},
1446 {6, {{0,0}, {1,-1}, {1,0}, {1,1}, {2,0}, {2,1}},
1447 4, {0, 1, 2, 3, -1, -1, -1, -1}, 4},
1452 {6, {{0,0}, {0,1}, {1,0}, {1,1}, {2,0}, {2,1}},
1453 2, {0, 1, -1, -1, -1, -1, -1, -1}, 3},
1459 {6, {{0,0}, {1,0}, {2,0}, {2,1}, {2,2}, {3,2}},
1460 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1466 {6, {{0,0}, {1,0}, {1,2}, {2,0}, {2,1}, {2,2}},
1467 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1473 {6, {{0,0}, {0,1}, {1,-1}, {1,0}, {2,0}, {2,1}},
1474 4, {0, 1, 2, 3, -1, -1, -1, -1}, 3},
1480 {6, {{0,0}, {0,1}, {1,0}, {2,-1}, {2,0}, {3,-1}},
1481 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1487 {6, {{0,0}, {0,1}, {1,-1}, {1,0}, {2,-1}, {2,0}},
1488 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3},
1494 {6, {{0,0}, {1,0}, {1,1}, {2,1}, {2,2}, {3,2}},
1495 4, {0, 1, 4, 5, -1, -1, -1, -1}, 3}};
1497 static struct pentomino_struct one_sided_pentomino[60];
1499 static void make_one_sided_pentomino(void)
1504 for (i=0;i<18;i++) {
1505 one_sided_pentomino[j] = pentomino[i];
1507 if (one_sided_pentomino[j].transform_list[t]>=4) {
1508 one_sided_pentomino[j].transform_len = t;
1510 one_sided_pentomino[j] = pentomino[i];
1511 for (u=t;u<8;u++) one_sided_pentomino[j].transform_list[u-t] = one_sided_pentomino[j].transform_list[u];
1512 one_sided_pentomino[j].transform_len -= t;
1519 static struct hexomino_struct one_sided_hexomino[60];
1521 static void make_one_sided_hexomino(void)
1526 for (i=0;i<35;i++) {
1527 one_sided_hexomino[j] = hexomino[i];
1529 if (one_sided_hexomino[j].transform_list[t]>=4) {
1530 one_sided_hexomino[j].transform_len = t;
1532 one_sided_hexomino[j] = hexomino[i];
1533 for (u=t;u<8;u++) one_sided_hexomino[j].transform_list[u-t] = one_sided_hexomino[j].transform_list[u];
1534 one_sided_hexomino[j].transform_len -= t;
1542 Find all the ways of placing all twelve pentominoes
1543 into a rectangle whose size is 20x3, 15x4, 12x5 or 10x6.
1547 int set_pentomino_puzzle(polyominoesstruct *sp)
1549 int perm_poly[12], perm_point[5], perm_transform[8], i, p;
1570 sp->nr_polyominoes = 12;
1571 set_allocate(sp->polyomino,polyomino_type,12*sizeof(polyomino_type));
1572 random_permutation(12,perm_poly);
1573 for (p=0;p<12;p++) {
1574 copy_polyomino(sp->polyomino[p],pentomino[perm_poly[p]],1);
1577 sp->check_ok = check_pentomino_puzzle;
1583 Many of the following puzzles are inspired by
1584 http://www.xs4all.nl/~gp/PolyominoSolver/Polyomino.html
1588 Find all the ways of placing all eighteen one-sided pentominoes
1593 int set_one_sided_pentomino_puzzle(polyominoesstruct *sp)
1595 int perm_poly[18], perm_point[5], perm_transform[8], i, p;
1597 make_one_sided_pentomino();
1618 sp->nr_polyominoes = 18;
1619 set_allocate(sp->polyomino,polyomino_type,18*sizeof(polyomino_type));
1620 random_permutation(18,perm_poly);
1621 for (p=0;p<18;p++) {
1622 copy_polyomino(sp->polyomino[p],one_sided_pentomino[perm_poly[p]],1);
1625 sp->check_ok = check_pentomino_puzzle;
1631 Find all the ways of placing all sixty one-sided hexominoes
1636 int set_one_sided_hexomino_puzzle(polyominoesstruct *sp)
1638 int perm_poly[60], perm_point[6], perm_transform[8], i, p;
1640 make_one_sided_hexomino();
1677 sp->nr_polyominoes = 60;
1678 set_allocate(sp->polyomino,polyomino_type,60*sizeof(polyomino_type));
1679 random_permutation(60,perm_poly);
1680 for (p=0;p<60;p++) {
1681 copy_polyomino(sp->polyomino[p],one_sided_hexomino[perm_poly[p]],1);
1684 sp->check_ok = check_hexomino_puzzle;
1690 Find all the ways of placing all five tetrominoes and all twelve
1691 pentominoes into a rectangle.
1695 int set_tetr_pentomino_puzzle(polyominoesstruct *sp)
1697 int perm_poly[17], perm_point[5], perm_transform[8], i, p;
1714 sp->nr_polyominoes = 17;
1715 set_allocate(sp->polyomino,polyomino_type,17*sizeof(polyomino_type));
1716 random_permutation(17,perm_poly);
1718 copy_polyomino(sp->polyomino[perm_poly[p]],tetromino[p],1);
1720 for (p=0;p<12;p++) {
1721 copy_polyomino(sp->polyomino[perm_poly[p+5]],pentomino[p],1);
1724 sp->check_ok = check_tetr_pentomino_puzzle;
1729 Find all the ways of placing all twelve pentominoes and all thirty five
1730 hexominoes into a rectangle whose size is 18x15.
1734 int set_pent_hexomino_puzzle(polyominoesstruct *sp)
1736 int perm_poly[47], perm_point[6], perm_transform[8], i, p;
1761 sp->nr_polyominoes = 47;
1762 set_allocate(sp->polyomino,polyomino_type,47*sizeof(polyomino_type));
1763 random_permutation(47,perm_poly);
1764 for (p=0;p<12;p++) {
1765 copy_polyomino(sp->polyomino[perm_poly[p]],pentomino[p],1);
1767 for (p=0;p<35;p++) {
1768 copy_polyomino(sp->polyomino[perm_poly[p+12]],hexomino[p],1);
1771 sp->check_ok = check_pent_hexomino_puzzle;
1779 Science News September 20, 1986 Vol 130, No 12
1780 Science News November 14, 1987 Vol 132, Pg 310
1786 **** fills a 10x5 rectangle
1790 static struct {int len; point_type point[5];
1791 int transform_len, transform_list[8], max_white;} pentomino1 =
1792 {5, {{0,0}, {1,0}, {2,0}, {3,0}, {1,1}},
1793 8, {0, 1, 2, 3, 4, 5, 6, 7}, 3};
1796 int set_pentomino_puzzle1(polyominoesstruct *sp)
1798 int perm_point[5], perm_transform[8], i, p;
1803 sp->nr_polyominoes = 10;
1804 set_allocate(sp->polyomino,polyomino_type,10*sizeof(polyomino_type));
1805 for (p=0;p<10;p++) {
1806 copy_polyomino(sp->polyomino[p],pentomino1,1);
1809 sp->check_ok = check_pentomino_puzzle;
1817 ***** fills a 24x23 rectangle
1821 static struct {int len; point_type point[6];
1822 int transform_len, transform_list[8], max_white;} hexomino1 =
1823 {6, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {1,1}},
1824 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4};
1827 int set_hexomino_puzzle1(polyominoesstruct *sp)
1829 int perm_point[6], perm_transform[8], i, p;
1834 sp->nr_polyominoes = 92;
1835 set_allocate(sp->polyomino,polyomino_type,92*sizeof(polyomino_type));
1836 for (p=0;p<92;p++) {
1837 copy_polyomino(sp->polyomino[p],hexomino1,1);
1840 sp->check_ok = check_hexomino_puzzle;
1848 ***** fills a 21x26 rectangle
1850 (All solutions have 180 degree rotational symmetry)
1854 static struct {int len; point_type point[7];
1855 int transform_len, transform_list[8], max_white;} heptomino1 =
1856 {7, {{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {1,1}, {2,1}},
1857 8, {0, 1, 2, 3, 4, 5, 6, 7}, 4};
1860 int set_heptomino_puzzle1(polyominoesstruct *sp)
1862 int perm_point[7], perm_transform[8], i, p;
1869 sp->nr_polyominoes = 78;
1870 set_allocate(sp->polyomino,polyomino_type,78*sizeof(polyomino_type));
1871 for (p=0;p<78;p+=2) {
1872 copy_polyomino(sp->polyomino[p],heptomino1,1);
1873 copy_polyomino(sp->polyomino[p+1],heptomino1,0);
1876 sp->check_ok = check_heptomino_puzzle;
1881 /* The following puzzles from
1882 Polyominoes Puzzles, Patterns, Problems, and Packings Revised (2nd) Edition
1883 by Solomon W. Golomb Princeton University Press 1994
1889 ***** fills a 28x19 rectangle
1893 int set_heptomino_puzzle2(polyominoesstruct *sp)
1895 int perm_point[7], perm_transform[8], i, p;
1900 sp->nr_polyominoes = 76;
1901 set_allocate(sp->polyomino,polyomino_type,76*sizeof(polyomino_type));
1902 for (p=0;p<76;p++) {
1903 copy_polyomino(sp->polyomino[p],heptomino1,1);
1906 sp->check_ok = check_heptomino_puzzle;
1914 **** fills a 25x22 rectangle
1919 static struct {int len; point_type point[11];
1920 int transform_len, transform_list[8], max_white;} elevenomino1 =
1921 {11, {{0,0}, {1,0}, {2,0},
1922 {0,1}, {1,1}, {2,1}, {3,1},
1923 {0,2}, {1,2}, {2,2}, {3,2}},
1924 8, {0, 1, 2, 3, 4, 5, 6, 7}, 6};
1927 int set_elevenomino_puzzle1(polyominoesstruct *sp)
1929 int perm_point[11], perm_transform[8], i, p;
1936 sp->nr_polyominoes = 50;
1937 set_allocate(sp->polyomino,polyomino_type,50*sizeof(polyomino_type));
1938 for (p=0;p<50;p+=2) {
1939 copy_polyomino(sp->polyomino[p],elevenomino1,1);
1940 copy_polyomino(sp->polyomino[p+1],elevenomino1,0);
1943 sp->check_ok = check_elevenomino_puzzle;
1952 **** fills 32 x 30 rectangle
1957 static struct {int len; point_type point[10];
1958 int transform_len, transform_list[8], max_white;} dekomino1 =
1961 {0,1}, {1,1}, {2,1}, {3,1},
1962 {0,2}, {1,2}, {2,2}, {3,2}},
1963 8, {0, 1, 2, 3, 4, 5, 6, 7}, 5};
1966 int set_dekomino_puzzle1(polyominoesstruct *sp)
1968 int perm_point[10], perm_transform[8], i, p;
1973 sp->nr_polyominoes = 96;
1974 set_allocate(sp->polyomino,polyomino_type,96*sizeof(polyomino_type));
1975 for (p=0;p<96;p++) {
1976 copy_polyomino(sp->polyomino[p],dekomino1,1);
1979 sp->check_ok = check_dekomino_puzzle;
1987 *** fills 96 x 26 rectangle
1992 static struct {int len; point_type point[10];
1993 int transform_len, transform_list[8], max_white;} octomino1 =
1995 {0,1}, {1,1}, {2,1},
1996 {0,2}, {1,2}, {2,2}, {3,2}},
1997 8, {0, 1, 2, 3, 4, 5, 6, 7}, 5};
2000 int set_octomino_puzzle1(polyominoesstruct *sp)
2002 int perm_point[8], perm_transform[8], i, p;
2007 sp->nr_polyominoes = 312;
2008 set_allocate(sp->polyomino,polyomino_type,312*sizeof(polyomino_type));
2009 for (p=0;p<312;p++) {
2010 copy_polyomino(sp->polyomino[p],octomino1,1);
2013 sp->check_ok = check_octomino_puzzle;
2020 * fills 15 x 15 rectangle
2026 int set_pentomino_puzzle2(polyominoesstruct *sp)
2028 int perm_point[5], perm_transform[8], i, p;
2033 sp->nr_polyominoes = 45;
2034 set_allocate(sp->polyomino,polyomino_type,45*sizeof(polyomino_type));
2035 for (p=0;p<45;p++) {
2036 copy_polyomino(sp->polyomino[p],pentomino1,1);
2039 sp->check_ok = check_pentomino_puzzle;
2047 **** fills a 47x33 rectangle
2053 int set_elevenomino_puzzle2(polyominoesstruct *sp)
2055 int perm_point[11], perm_transform[8], i, p;
2060 sp->nr_polyominoes = 141;
2061 set_allocate(sp->polyomino,polyomino_type,141*sizeof(polyomino_type));
2062 for (p=0;p<141;p++) {
2063 copy_polyomino(sp->polyomino[p],elevenomino1,1);
2066 sp->check_ok = check_elevenomino_puzzle;
2071 /**************************************************
2073 **************************************************/
2075 #define allocate(p,type,size) p = (type *) malloc(size); if ((p)==NULL) {free_polyominoes(sp); return;}
2078 init_polyominoes (ModeInfo * mi)
2080 polyominoesstruct *sp;
2085 if (polyominoeses == NULL) {
2087 = (polyominoesstruct *) calloc(MI_NUM_SCREENS(mi),sizeof (polyominoesstruct)))
2091 sp = &polyominoeses[MI_SCREEN(mi)];
2093 free_polyominoes(sp);
2098 if (MI_IS_FULLRANDOM(mi)) {
2099 sp->identical = (Bool) (LRAND() & 1);
2100 sp->use3D = (Bool) (NRAND(4));
2102 sp->identical = identical;
2105 if (sp->identical) {
2108 if (!set_pentomino_puzzle1(sp))
2112 if (!set_hexomino_puzzle1(sp))
2116 if (!set_heptomino_puzzle1(sp))
2120 if (!set_heptomino_puzzle2(sp))
2124 if (!set_elevenomino_puzzle1(sp))
2128 if (!set_dekomino_puzzle1(sp))
2132 if (!set_octomino_puzzle1(sp))
2136 if (!set_pentomino_puzzle2(sp))
2140 if (!set_elevenomino_puzzle2(sp))
2147 if (!set_pentomino_puzzle(sp))
2151 if (!set_one_sided_pentomino_puzzle(sp))
2155 if (!set_one_sided_hexomino_puzzle(sp))
2159 if (!set_pent_hexomino_puzzle(sp))
2163 if (!set_tetr_pentomino_puzzle(sp))
2169 allocate(sp->attach_list,int,sp->nr_polyominoes*sizeof(int));
2170 sp->nr_attached = 0;
2172 if (sp->identical) {
2173 allocate(sp->reason_to_not_attach,int,sp->nr_polyominoes*sp->nr_polyominoes*sizeof(int));
2176 allocate(sp->array,int,sp->width*sp->height*sizeof(int));
2177 allocate(sp->changed_array,int,sp->width*sp->height*sizeof(int));
2178 for (x=0;x<sp->width;x++) for (y=0;y<sp->height;y++) ARRAY(x,y) = -1;
2180 sp->left_right = NRAND(2);
2181 sp->top_bottom = NRAND(2);
2183 box1 = MI_WIDTH(mi)/(sp->width+2);
2184 box2 = MI_HEIGHT(mi)/(sp->height+2);
2190 if (sp->box >= 12) {
2191 sp->box = (sp->box/12)*12;
2192 create_bitmaps(mi,sp);
2193 if (!sp->use_bitmaps)
2197 sp->use_bitmaps = 0;
2199 if (!sp->use_bitmaps) {
2200 allocate(sp->rectangles,XRectangle,sp->width*sp->height*sizeof(XRectangle));
2201 allocate(sp->lines,XSegment,sp->width*sp->height*sizeof(XSegment));
2204 allocate(perm,int,sp->nr_polyominoes*sizeof(int));
2205 random_permutation(sp->nr_polyominoes, perm);
2206 sp->mono = MI_NPIXELS(mi) < 12;
2207 start = NRAND(MI_NPIXELS(mi));
2208 for (i=0;i<sp->nr_polyominoes;i++)
2210 sp->polyomino[i].color = MI_PIXEL(mi,(perm[i]*MI_NPIXELS(mi) / sp->nr_polyominoes + start) % MI_NPIXELS(mi));
2212 sp->polyomino[i+1].color = sp->polyomino[i].color;
2218 sp->polyomino[i].color = MI_WHITE_PIXEL(mi);
2220 sp->polyomino[i].color = MI_BLACK_PIXEL(mi);
2223 if (sp->use_bitmaps) {
2225 sp->border_color = MI_WHITE_PIXEL(mi);
2227 sp->border_color = MI_PIXEL(mi,NRAND(MI_NPIXELS(mi)));
2230 sp->x_margin = (MI_WIDTH(mi)-sp->box*sp->width)/2;
2231 sp->y_margin = (MI_HEIGHT(mi)-sp->box*sp->height)/2;
2236 /* Clear the background. */
2243 draw_polyominoes (ModeInfo * mi)
2245 polyominoesstruct *sp;
2246 int poly_no,point_no,transform_index,done,another_attachment_try;
2247 point_type attach_point;
2250 if (polyominoeses == NULL)
2252 sp = &polyominoeses[MI_SCREEN(mi)];
2256 sp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), sp->eraser);
2261 if (MI_CYCLES(mi) != 0) {
2262 if (++sp->counter > MI_CYCLES(mi)) {
2264 sp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), sp->eraser);
2265 #endif /* STANDALONE */
2266 init_polyominoes(mi);
2273 sp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), sp->eraser);
2274 #endif /* STANDALONE */
2275 init_polyominoes(mi);
2279 MI_IS_DRAWN(mi) = True;
2281 if (sp->wait>0) return;
2283 memset(sp->changed_array,0,sp->width*sp->height*sizeof(int));
2285 poly_no = first_poly_no(sp);
2287 transform_index = 0;
2289 another_attachment_try = 1;
2290 find_blank(sp,&attach_point);
2291 if (sp->identical && sp->nr_attached < sp->nr_polyominoes)
2292 memset(&REASON_TO_NOT_ATTACH(sp->nr_attached,0),0,sp->nr_polyominoes*sizeof(int));
2294 if (sp->nr_attached < sp->nr_polyominoes) {
2295 while (!done && another_attachment_try) {
2296 done = attach(sp,poly_no,point_no,transform_index,attach_point,0,&REASON_TO_NOT_ATTACH(sp->nr_attached,0));
2297 if (done && sp->rot180) {
2298 poly_no = first_poly_no(sp);
2299 done = attach(sp,poly_no,point_no,transform_index,attach_point,1,&REASON_TO_NOT_ATTACH(sp->nr_attached-1,0));
2301 detach(sp,&poly_no,&point_no,&transform_index,&attach_point,0);
2304 another_attachment_try = next_attach_try(sp,&poly_no,&point_no,&transform_index);
2308 if (sp->identical) {
2310 if (sp->nr_attached == 0)
2313 detach_until=sp->nr_attached-1;
2314 if (sp->nr_attached < sp->nr_polyominoes)
2315 while (detach_until>0 && REASON_TO_NOT_ATTACH(sp->nr_attached,detach_until)==0)
2317 while (sp->nr_attached>detach_until) {
2319 detach(sp,&poly_no,&point_no,&transform_index,&attach_point,1);
2320 detach(sp,&poly_no,&point_no,&transform_index,&attach_point,0);
2321 if (sp->nr_attached+1+sp->rot180 < sp->nr_polyominoes)
2322 for (i=0;i<sp->nr_polyominoes;i++)
2323 REASON_TO_NOT_ATTACH(sp->nr_attached,i) |= REASON_TO_NOT_ATTACH(sp->nr_attached+1+sp->rot180,i);
2325 another_attachment_try = next_attach_try(sp,&poly_no,&point_no,&transform_index);
2331 if (sp->nr_attached == 0)
2335 detach(sp,&poly_no,&point_no,&transform_index,&attach_point,1);
2336 detach(sp,&poly_no,&point_no,&transform_index,&attach_point,0);
2338 another_attachment_try = next_attach_try(sp,&poly_no,&point_no,&transform_index);
2343 if (sp->use_bitmaps)
2344 draw_with_bitmaps(mi,sp);
2346 draw_without_bitmaps(mi,sp);
2348 if (sp->nr_attached == sp->nr_polyominoes)
2355 release_polyominoes(ModeInfo * mi)
2359 if (polyominoeses != NULL) {
2360 for (screen=0;screen<MI_NUM_SCREENS(mi); screen++)
2361 free_polyominoes(&polyominoeses[screen]);
2362 (void) free((void *) polyominoeses);
2363 polyominoeses = (polyominoesstruct *) NULL;
2368 refresh_polyominoes (ModeInfo * mi)
2373 XSCREENSAVER_MODULE ("Polyominoes", polyominoes)
2375 #endif /* MODE_polyominoes */