2307 lines
60 KiB
C
2307 lines
60 KiB
C
|
/* -*- Mode: C; tab-width: 4 -*- */
|
||
|
/* polyominoes --- Shows attempts to place polyominoes into a rectangle */
|
||
|
|
||
|
#if !defined( lint ) && !defined( SABER )
|
||
|
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 PROGCLASS "Polyominoes"
|
||
|
#define HACK_INIT init_polyominoes
|
||
|
#define HACK_DRAW draw_polyominoes
|
||
|
#define polyominoes_opts xlockmore_opts
|
||
|
#define DEFAULTS "*delay: 1000 \n" \
|
||
|
"*count: 1024 \n" \
|
||
|
"*cycles: 3000 \n" \
|
||
|
"*ncolors: 200 \n"
|
||
|
#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;
|
||
|
|
||
|
static XrmOptionDescRec opts[] =
|
||
|
{
|
||
|
{(char *) "-identical", (char *) ".polyominoes.identical", XrmoptionNoArg, (caddr_t) "on"},
|
||
|
{(char *) "+identical", (char *) ".polyominoes.identical", XrmoptionNoArg, (caddr_t) "off"},
|
||
|
{(char *) "-plain", (char *) ".polyominoes.plain", XrmoptionNoArg, (caddr_t) "on"},
|
||
|
{(char *) "+plain", (char *) ".polyominoes.plain", XrmoptionNoArg, (caddr_t) "off"}
|
||
|
};
|
||
|
static argtype vars[] =
|
||
|
{
|
||
|
{(void *) &identical, (char *) "identical", (char *) "Identical", (char *) DEF_IDENTICAL, t_Bool},
|
||
|
{(void *) & plain, (char *) "plain", (char *) "Plain", (char *) DEF_PLAIN, t_Bool}
|
||
|
};
|
||
|
static OptionStruct desc[] =
|
||
|
{
|
||
|
{(char *) "-/+identical", (char *) "turn on/off puzzles where the polyomino pieces are identical"},
|
||
|
{(char *) "-/+plain", (char *) "turn on/off plain pieces"}
|
||
|
};
|
||
|
|
||
|
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", "release_polyominoes",
|
||
|
"refresh_polyominoes", "init_polyominoes", (char *) NULL, &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)
|
||
|
(void) fprintf(stderr," ");
|
||
|
else
|
||
|
(void) fprintf(stderr,"%c",'a'+ARRAY(x,y));
|
||
|
(void) fprintf(stderr,"\n");
|
||
|
}
|
||
|
(void) fprintf(stderr,"\n");
|
||
|
}
|
||
|
|
||
|
static void print_points(point_type *point, int len) {
|
||
|
int i;
|
||
|
|
||
|
for (i=0;i<len;i++)
|
||
|
(void) 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);
|
||
|
(void) fprintf(stderr,"\n");
|
||
|
for (i=0;i<poly.transform_len;i++)
|
||
|
(void) fprintf(stderr,"%d ",poly.transform_list[i]);
|
||
|
(void) 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, target_point;
|
||
|
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;
|
||
|
|
||
|
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;
|
||
|
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);
|
||
|
XFlush(display);
|
||
|
}
|
||
|
|
||
|
static void create_bitmaps(ModeInfo * mi, polyominoesstruct *sp) {
|
||
|
int x,y,n;
|
||
|
char *data;
|
||
|
|
||
|
for (n=0;n<256;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);
|
||
|
XFlush(display);
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************
|
||
|
Routines to initialise and close down polyominoes.
|
||
|
***************************************************/
|
||
|
|
||
|
static void free_bitmaps(polyominoesstruct *sp) {
|
||
|
int n;
|
||
|
|
||
|
for (n=0;n<256;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;}
|
||
|
|
||
|
static void free_polyominoes(polyominoesstruct *sp) {
|
||
|
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(sp);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<18;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<35;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(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,12*sizeof(polyomino_type));
|
||
|
random_permutation(12,perm_poly);
|
||
|
for (p=0;p<12;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(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,18*sizeof(polyomino_type));
|
||
|
random_permutation(18,perm_poly);
|
||
|
for (p=0;p<18;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(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,60*sizeof(polyomino_type));
|
||
|
random_permutation(60,perm_poly);
|
||
|
for (p=0;p<60;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(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,17*sizeof(polyomino_type));
|
||
|
random_permutation(17,perm_poly);
|
||
|
for (p=0;p<5;p++) {
|
||
|
copy_polyomino(sp->polyomino[perm_poly[p]],tetromino[p],1);
|
||
|
}
|
||
|
for (p=0;p<12;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(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<12;p++) {
|
||
|
copy_polyomino(sp->polyomino[perm_poly[p]],pentomino[p],1);
|
||
|
}
|
||
|
for (p=0;p<35;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(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,10*sizeof(polyomino_type));
|
||
|
for (p=0;p<10;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(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,92*sizeof(polyomino_type));
|
||
|
for (p=0;p<92;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(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,78*sizeof(polyomino_type));
|
||
|
for (p=0;p<78;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(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,76*sizeof(polyomino_type));
|
||
|
for (p=0;p<76;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(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,50*sizeof(polyomino_type));
|
||
|
for (p=0;p<50;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(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,96*sizeof(polyomino_type));
|
||
|
for (p=0;p<96;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(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,312*sizeof(polyomino_type));
|
||
|
for (p=0;p<312;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(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,45*sizeof(polyomino_type));
|
||
|
for (p=0;p<45;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(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,141*sizeof(polyomino_type));
|
||
|
for (p=0;p<141;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(sp); return;}
|
||
|
|
||
|
void
|
||
|
init_polyominoes(ModeInfo * mi) {
|
||
|
polyominoesstruct *sp;
|
||
|
int i,x,y, start;
|
||
|
int box1, box2;
|
||
|
int *perm;
|
||
|
|
||
|
if (polyominoeses == NULL) {
|
||
|
if ((polyominoeses
|
||
|
= (polyominoesstruct *) calloc(MI_NUM_SCREENS(mi),sizeof (polyominoesstruct)))
|
||
|
== NULL)
|
||
|
return;
|
||
|
}
|
||
|
sp = &polyominoeses[MI_SCREEN(mi)];
|
||
|
|
||
|
free_polyominoes(sp);
|
||
|
|
||
|
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(sp))
|
||
|
return;
|
||
|
break;
|
||
|
case 1:
|
||
|
if (!set_hexomino_puzzle1(sp))
|
||
|
return;
|
||
|
break;
|
||
|
case 2:
|
||
|
if (!set_heptomino_puzzle1(sp))
|
||
|
return;
|
||
|
break;
|
||
|
case 3:
|
||
|
if (!set_heptomino_puzzle2(sp))
|
||
|
return;
|
||
|
break;
|
||
|
case 4:
|
||
|
if (!set_elevenomino_puzzle1(sp))
|
||
|
return;
|
||
|
break;
|
||
|
case 5:
|
||
|
if (!set_dekomino_puzzle1(sp))
|
||
|
return;
|
||
|
break;
|
||
|
case 6:
|
||
|
if (!set_octomino_puzzle1(sp))
|
||
|
return;
|
||
|
break;
|
||
|
case 7:
|
||
|
if (!set_pentomino_puzzle2(sp))
|
||
|
return;
|
||
|
break;
|
||
|
case 8:
|
||
|
if (!set_elevenomino_puzzle2(sp))
|
||
|
return;
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
switch (NRAND(5)) {
|
||
|
case 0:
|
||
|
if (!set_pentomino_puzzle(sp))
|
||
|
return;
|
||
|
break;
|
||
|
case 1:
|
||
|
if (!set_one_sided_pentomino_puzzle(sp))
|
||
|
return;
|
||
|
break;
|
||
|
case 2:
|
||
|
if (!set_one_sided_hexomino_puzzle(sp))
|
||
|
return;
|
||
|
break;
|
||
|
case 3:
|
||
|
if (!set_pent_hexomino_puzzle(sp))
|
||
|
return;
|
||
|
break;
|
||
|
case 4:
|
||
|
if (!set_tetr_pentomino_puzzle(sp))
|
||
|
return;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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 (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);
|
||
|
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
|
||
|
(void) 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)
|
||
|
(void) 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 = 500;
|
||
|
else
|
||
|
sp->wait = 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
release_polyominoes(ModeInfo * mi) {
|
||
|
int screen;
|
||
|
|
||
|
if (polyominoeses != NULL) {
|
||
|
for (screen=0;screen<MI_NUM_SCREENS(mi); screen++)
|
||
|
free_polyominoes(&polyominoeses[screen]);
|
||
|
free(polyominoeses);
|
||
|
polyominoeses = (polyominoesstruct *) NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
refresh_polyominoes(ModeInfo * mi) {
|
||
|
MI_CLEARWINDOW(mi);
|
||
|
}
|
||
|
|
||
|
#endif /* MODE_polyominoes */
|