struct
{
char name;
int size;
int nr_neighbours; // = size - 1, except for 'g'
} pieces[8] =
{
{ 'o', 5, 4 },
{ 'r', 4, 3 },
{ 'e', 4, 3 },
{ 'b', 4, 3 },
{ 'g', 4, 4 },
{ 'z', 4, 3 },
{ 'w', 3, 2 },
{ 'p', 2, 1 }
};
int height = 10;
int multiplicity = 5;
void print_puzzle_name(FILE *f, const char *name, bool capital)
{
int n = strlen(name);
for (int i = 0; i < n; i++)
{
if (i == 0)
;
else if (i < n-1)
fprintf(f, ", ");
else if (n == 2)
fprintf(f, " and ");
else
fprintf(f, ", and ");
switch (name[i])
{
case 'g': fprintf(f, "%s", capital ? "Green" : "green"); break;
case 'z': fprintf(f, "%s", capital ? "Black" : "black"); break;
case 'r': fprintf(f, "%s", capital ? "Red" : "red"); break;
case 'b': fprintf(f, "%s", capital ? "Blue" : "blue"); break;
case 'w': fprintf(f, "%s", capital ? "White" : "white"); break;
case 'p': fprintf(f, "%s", capital ? "Purple" : "purple"); break;
case 'o': fprintf(f, "%s", capital ? "Orange" : "orange"); break;
case 'e': fprintf(f, "%s", capital ? "Yellow" : "yellow"); break;
}
capital = false;
}
}
class PrintNumber
{
public:
PrintNumber(long long n, bool capital = false, const char *one = "", const char *more = "")
{
static const char *numnames[22] = {
"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten",
"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"
};
if (n < 0)
sprintf(buffer, "ERROR");
else if (n == 0)
sprintf(buffer, "%s %s", capital?"No":"no", more);
else if (n <= 10)
sprintf(buffer, "%s %s", numnames[n+(capital?-1:9)], n == 1 ? one : more);
else if (n <= 999)
sprintf(buffer, "%lld %s", n, more);
else if (n <= 999999L)
sprintf(buffer, "%lld,%03lld %s", n/1000, n%1000, more);
else if (n <= 999999999LL)
sprintf(buffer, "%lld,%03lld,%03lld %s", n/1000000L, (n/1000)%1000, n%1000, more);
else
sprintf(buffer, "%lld,%03lld,%03lld,%03lld %s", n/1000000000L, (n/1000000L)%1000, (n/1000)%1000, n%1000, more);
}
const char *val() { return buffer; }
private:
char buffer[200];
};
int pieces_bv_for(const char *name)
{
int pieces_bv = 0;
const char *s = name;
for (int i = 0; i < 8; i++)
{
if (*s == pieces[i].name)
{
pieces_bv |= (1 << i);
s++;
}
}
return pieces_bv;
}
int abs_min_neighbours_for(const char *name)
{
int neighbours = 0;
const char *s = name;
for (int i = 0; i < 8; i++)
{
if (*s == pieces[i].name)
{
neighbours += multiplicity * pieces[i].nr_neighbours + multiplicity - 1;
s++;
}
}
return neighbours;
}
class Puzzle
{
public:
static Puzzle *add(const char *name, int width)
{
Puzzle *new_puzzle = *ref_last = new Puzzle(name, width);
ref_last = &(*ref_last)->next;
return new_puzzle;
}
char name[10];
int width;
int pieces_bv;
int abs_min_neighbours;
int min_neighbours;
int nr_min_neighbours;
int max_neighbours;
int nr_max_neighbours;
long long patterns;
bool unknown;
long long count4;
long long count2;
long long count1;
long long count;
long long mix_count;
long long guess_count;
class Iterator
{
public:
Iterator() : _it(Puzzle::all) {}
bool more() const { return _it != 0; }
void next() { _it = _it->next; }
Puzzle& val() const { return *_it; }
private:
Puzzle *_it;
};
friend class Puzzle::Iterator;
private:
struct Line
{
Line(const char *ns, int width) : next(0)
{
s = new char[strlen(ns)+1]; strcpy(s, ns);
neighbours = 0;
for (int h = 1; h < width; h++)
for (int v = 0; v < height; v++)
if (s[v*width+h-1] == s[v*width+h])
neighbours++;
for (int h = 0; h < width; h++)
for (int v = 1; v < height; v++)
if (s[(v-1)*width+h] == s[v*width+h])
neighbours++;
}
char *s;
int neighbours;
Line * next;
};
public:
void addLine(const char *line)
{
Line* new_line = new Line(line, width);
*ref_line = new_line;
ref_line = &(*ref_line)->next;
if (min_neighbours == 0 || new_line->neighbours < min_neighbours)
{
min_neighbours = new_line->neighbours;
nr_min_neighbours = 1;
}
else if (new_line->neighbours == min_neighbours)
nr_min_neighbours++;
if (max_neighbours == 0 || new_line->neighbours > max_neighbours)
{
max_neighbours = new_line->neighbours;
nr_max_neighbours = 1;
}
else if (new_line->neighbours == max_neighbours)
nr_max_neighbours++;
}
class LineIterator
{
public:
LineIterator(const Puzzle &puzzle) : line(puzzle.lines) {}
bool more() const { return line != 0; }
void next() { line = line->next; }
const char* val() { return line->s; }
int neighbours() { return line->neighbours; }
private:
Line* line;
};
friend class Puzzle::LineIterator;
private:
class Combination
{
public:
Combination(Puzzle* p[], int nr_p, long long c, long long nc, int min_n, int nr_min_n, int max_n, int nr_max_n)
: nr_parts(nr_p), count(c), norm_count(nc), next(0),
min_neighbours(min_n), nr_min_neighbours(nr_min_n),
max_neighbours(max_n), nr_max_neighbours(nr_max_n)
{
for (int i = 0; i < nr_parts; i++)
parts[i] = p[i];
}
Puzzle* parts[10];
int nr_parts;
long long count;
long long norm_count;
int min_neighbours;
int nr_min_neighbours;
int max_neighbours;
int nr_max_neighbours;
Combination* next;
void print(FILE *f)
{
fprintf(f, "%s (%s) are permutations of ",
PrintNumber(count, true, "solution", "solutions").val(),
PrintNumber(norm_count, false, "normalized solution", "normalized solutions").val());
for (int i = 0; i < nr_parts; i++)
{
if (i == 0)
;
else if (i < nr_parts)
fprintf(f, ", ");
else if (nr_parts == 2)
fprintf(f, " and ");
else
fprintf(f, ", and ");
fprintf(f, "%s of ",
PrintNumber(parts[i]->mix_count, false, "solution", "solutions").val(),
parts[i]->name);
print_puzzle_name(f, parts[i]->name, false);
fprintf(f, "");
}
fprintf(f, ".\n");
}
};
public:
void addCombination(Puzzle* parts[], int nr_parts, long long count, long long norm_count, int min_n, int nr_min_n, int max_n, int nr_max_n)
{
*ref_combination = new Combination(parts, nr_parts, count, norm_count, min_n, nr_min_n, max_n, nr_max_n);
ref_combination = &(*ref_combination)->next;
}
class CombinationIterator
{
public:
CombinationIterator(const Puzzle &puzzle) : combination(puzzle.combinations) {}
bool more() const { return combination != 0; }
void next() { combination = combination->next; }
Puzzle* part(int i) const { return combination->parts[i]; }
Puzzle** parts() const { return combination->parts; }
int nr_parts() const { return combination->nr_parts; }
long long count() const { return combination->count; }
long long norm_count() const { return combination->norm_count; }
int min_neighbours() const { return combination->min_neighbours; }
int nr_min_neighbours() const { return combination->nr_min_neighbours; }
int max_neighbours() const { return combination->max_neighbours; }
int nr_max_neighbours() const { return combination->nr_max_neighbours; }
void print(FILE *f) { combination->print(f); }
private:
Combination* combination;
};
friend class Puzzle::CombinationIterator;
private:
Puzzle(const char* n, int w)
: width(w), pieces_bv(pieces_bv_for(n)), abs_min_neighbours(abs_min_neighbours_for(n)), min_neighbours(0), nr_min_neighbours(0),
patterns(0),
unknown(false), count(0), count4(0), count2(0), count1(0), mix_count(0), next(0), lines(0), combinations(0)
{
strcpy(name, n);
ref_line = &lines;
ref_combination = &combinations;
}
Puzzle *next;
Line* lines;
Line** ref_line;
Combination* combinations;
Combination** ref_combination;
static Puzzle *all;
static Puzzle **ref_last;
};
Puzzle *Puzzle::all = 0;
Puzzle **Puzzle::ref_last = &Puzzle::all;
#define SUBSET(A,B) ((A)!=(B)&&((A)|(B))==(B))
void search_combined(int pieces_bv, int width, int depth, Puzzle *parts[], Puzzle &puzzle)
{
for (Puzzle::Iterator it; it.more(); it.next())
{
if (it.val().pieces_bv == pieces_bv)
{
if (depth > 0 && it.val().mix_count > 0)
{
parts[depth] = &it.val();
long long count = 1;
int min_neighbours = 0;
int nr_min_neighbours = 1;
int max_neighbours = 0;
int nr_max_neighbours = 1;
int factor = 2;
for (int i = 0; i <= depth; i++)
{
count *= parts[i]->mix_count * (i+1);
if (parts[i]->count > 1)
factor = 4;
min_neighbours += parts[i]->min_neighbours;
nr_min_neighbours *= parts[i]->nr_min_neighbours * (i+1);
max_neighbours += parts[i]->max_neighbours;
nr_max_neighbours *= parts[i]->nr_max_neighbours * (i+1);
}
long norm_count = count / factor;
//min_neighbours /= factor;
//max_neighbours /= factor;
puzzle.addCombination(parts, depth+1, count, norm_count, min_neighbours, nr_min_neighbours, max_neighbours, nr_max_neighbours);
}
break;
}
if (it.val().mix_count > 0 && it.val().width < width && SUBSET(it.val().pieces_bv, pieces_bv))
{
int rem_width = width - it.val().width;
int rem_pieces_bv = pieces_bv & ~it.val().pieces_bv;
if (rem_width <= it.val().width && (rem_width < it.val().width || rem_pieces_bv < it.val().pieces_bv))
{
parts[depth] = &it.val();
search_combined(rem_pieces_bv, rem_width, depth+1, parts, puzzle);
}
}
}
}
void print_min_max_neighbours(FILE* f, Puzzle& puzzle)
{
if (puzzle.max_neighbours == puzzle.min_neighbours)
return;
fprintf(f, "There %s ", puzzle.nr_min_neighbours == 1 ? "is" : "are");
int diff = puzzle.min_neighbours - puzzle.abs_min_neighbours;
if (diff == 0)
fprintf(f, "%s.\n",
PrintNumber(puzzle.nr_min_neighbours, false, "optimal minimal touching pattern", "optimal minimal touching patterns").val());
else
fprintf(f, "%s suboptimal with %s extra.\n",
PrintNumber(puzzle.nr_min_neighbours, false, "minimal touching pattern, which is", "minimal touching patterns, which are").val(),
PrintNumber(diff).val());
fprintf(f, "There %s %s.\n",
puzzle.nr_max_neighbours == 1 ? "is" : "are",
PrintNumber(puzzle.nr_max_neighbours, false, "maximal touching pattern", "maximal touching patterns").val());
}
void iterate_min_neighbours(FILE *f, Puzzle* parts[], int nr_parts, Puzzle::LineIterator* lines[], int depth, int &count)
{
if (depth == nr_parts)
{
if (f != 0)
{
fprintf(f,"p(\"");
for (int h = 0; h < height; h++)
for (int p = 0; p < nr_parts; p++)
{
int w = parts[p]->width;
for (int i = 0; i < w; i++)
fprintf(f, "%c", lines[p]->val()[w*h + i]);
}
fprintf(f,"\")\n");
}
else
count++;
return;
}
int min_neighbours = parts[depth]->min_neighbours;
for (Puzzle::LineIterator it(*parts[depth]); it.more(); it.next())
if (it.neighbours() == min_neighbours)
{
lines[depth] = ⁢
iterate_min_neighbours(f, parts, nr_parts, lines, depth+1, count);
}
}
void analyze(const char* fn)
{
FILE *f = fopen(fn,"rt");
if (f == 0)
{
printf("File '%s' could not be opened\n", fn);
return;
}
printf("Analyze contests of %s\n", fn);
char line[200];
int width;
int max_nr = 0;
while (fgets(line, 199, f))
{
if (strncmp(line, "\"width = ", 9) == 0)
{
width = atoi(line + 9);
printf("width = %d\n", width);
}
else if (line[0] == '"')
{
char name[10];
char *r = name;
for (char *s = line+1; *s != '"' && *s != '\0';)
*r++ = *s++;
*r = '\0';
fgets(line, 199, f);
long pieces_bv = 0;
Puzzle* puzzle = Puzzle::add(name, width);
if (line[0] == '?')
{
printf("Not calculated yet: %s\n", name);
fgets(line, 199, f);
puzzle->unknown = true;
}
else
{
while (line[0] != '"')
{
puzzle->patterns++;
int nr = atoi(line);
puzzle->count += nr;
if (nr % 4 == 0)
puzzle->count4 += nr / 4;
else if (nr % 2 == 0)
puzzle->count2 += nr / 2;
else
puzzle->count1 += nr;
if (nr > max_nr)
max_nr = nr;
*strstr(line, "\")") = '\0';
puzzle->addLine(line + 11);
fgets(line, 199, f);
}
printf("- %s %ld %ld", name, puzzle->patterns, puzzle->count);
if (puzzle->count1 > 0)
{
printf(" = 1 x %d", puzzle->count1);
if (puzzle->count2 > 0)
printf(" + 2 x %d", puzzle->count2);
if (puzzle->count4 > 0)
printf(" + 4 x %d", puzzle->count4);
}
else if (puzzle->count2 > 0)
{
printf(" = 2 x %d", puzzle->count2);
if (puzzle->count4 > 0)
printf(" + 4 x %d", puzzle->count4);
}
else if (puzzle->count4 > 0)
printf(" = 4 x %d", puzzle->count4);
printf("\n");
if (puzzle->count > 0)
pieces_bv = puzzle->pieces_bv;
}
if (pieces_bv != 0)
{
for (Puzzle::Iterator it; it.more(); it.next())
{
if ( it.val().count > 0
&& SUBSET(it.val().pieces_bv, pieces_bv))
{
long diff = pieces_bv & ~it.val().pieces_bv;
Puzzle::Iterator it2;
for (; it2.more(); it2.next())
if (it2.val().count > 0 && it2.val().pieces_bv == diff)
break;
if (it2.more())
{
if (it.val().pieces_bv < it2.val().pieces_bv)
printf(" - %s %lld %lld + %s %lld %lld\n",
it.val().name, it.val().patterns, it.val().count,
it2.val().name, it2.val().patterns, it2.val().count);
}
else
{
bool larger = false;
for (Puzzle::Iterator it2; it2.more(); it2.next())
if ( it2.val().count > 0
&& SUBSET(it2.val().pieces_bv, pieces_bv)
&& SUBSET(it.val().pieces_bv, it2.val().pieces_bv))
{
larger = true;
break;
}
if (!larger)
printf(" - %s %ld %ld\n", it.val().name, it.val().patterns, it.val().count);
}
}
}
}
if (line[0] != '"' && line[1] != '"')
printf("Unknown line: %s\n", line);
}
else
printf("Unknown line: %s\n", line);
}
printf("max_nr = %d\n", max_nr);
fclose(f);
char htmlfn[30];
sprintf(htmlfn, "CWP_N_%d.html", height);
f = fopen(htmlfn, "wt");
if (f == 0)
return;
printf("Generate file %s\n", htmlfn);
fprintf(f, "\n");
fprintf(f, "Chinese Wooden Puzzles in N by %d\n", height);
fprintf(f, "\n");
fprintf(f, "\n");
fprintf(f, "\n");
fprintf(f, "\n");
fprintf(f, "Chinese Wooden Puzzles in N by %d
\n", height);
fprintf(f, "\n");
fprintf(f, "Below the results for the Chinese Wooden Puzzle that fit in a frame of size\n");
fprintf(f, "N by %d for all possible values for N and combination of\n", height);
fprintf(f, "kind of pieces, where %d pieces of each selected kind are used.\n", multiplicity);
fprintf(f, "This page is generated with the program genCWP10.cpp\n");
width = -1;
for (Puzzle::Iterator it; it.more(); it.next())
{
Puzzle& puzzle = it.val();
if (puzzle.width > width)
{
width = puzzle.width;
fprintf(f, "\nChinese Wooden Puzzles in %d by %d
\n", width, height);
}
fprintf(f, "\n\n\n", PrintNumber(comb_count).val());
else
fprintf(f, ": Not calculated yet\n\n");
if (nr_comb > 0)
{
for (Puzzle::CombinationIterator it(puzzle); it.more(); it.next())
it.print(f);
fprintf(f, "Which means it has at least %s solutions (%s normalized solutions).\n",
PrintNumber(comb_count).val(), PrintNumber(comb_norm_count).val());
puzzle.guess_count = comb_count * 10;
int diff = min_neighbours - puzzle.abs_min_neighbours;
if (diff == 0)
fprintf(f, "There %s at least %s.\n",
nr_min_neighbours == 1 ? "is" : "are",
PrintNumber(nr_min_neighbours, false, "optimal minimal touching pattern", "optimal minimal touching patterns").val());
else
{
fprintf(f, "There exists at least minimal touching patterns with %s extra.\n",
PrintNumber(diff).val());
fprintf(f, "There %s at least %s.\n",
nr_min_neighbours == 1 ? "is" : "are",
PrintNumber(nr_min_neighbours, false, "such suboptimal minimal touching pattern", "such suboptimal minimal touching patterns").val());
//fprintf(f, "There %s %s.\n",
// puzzle.nr_max_neighbours == 1 ? "is" : "are",
// PrintNumber(puzzle.nr_max_neighbours, false, "maximal touching pattern", "maximal touching patterns").val());
}
int count = 0;
for (Puzzle::CombinationIterator it(puzzle); it.more(); it.next())
if (it.min_neighbours() == min_neighbours)
{
Puzzle::LineIterator* lines[10];
iterate_min_neighbours(0, it.parts(), it.nr_parts(), lines, 0, count);
}
int factor = 8;
int total_height = 0;
for (; factor > 1; factor--)
{
total_height = factor*height;
int sx = 0;
for (int i = 0; i < count; i++)
{
sx++;
if (factor*((width+2)*sx + width) >= 600) { sx = 0; total_height += factor*(height+2); }
}
if (total_height <= 800)
break;
}
if (total_height <= 800)
{
fprintf(f, "%s:\n", PrintNumber(count, true, "such pattern is", "such patterns are").val());
fprintf(f, "\n\n
\n");
fprintf(f, "\n");
}
}
else
{
long long count = 0;
for (Puzzle::Iterator it; it.more(); it.next())
{
if ( it.val().count > 0
&& SUBSET(it.val().pieces_bv, puzzle.pieces_bv))
{
bool larger = false;
for (Puzzle::Iterator it2; it2.more(); it2.next())
if ( it2.val().count > 0
&& SUBSET(it2.val().pieces_bv, puzzle.pieces_bv)
&& SUBSET(it.val().pieces_bv, it2.val().pieces_bv))
{
larger = true;
break;
}
if (!larger)
{
fprintf(f, "", it.val().name);
print_puzzle_name(f, it.val().name, true);
fprintf(f, " in %d by %d has %s solutions in %s patterns.\n",
it.val().width, height, PrintNumber(it.val().count).val(), PrintNumber(it.val().patterns).val());
count += it.val().count * 4 * width / it.val().width;
}
}
}
puzzle.guess_count = count;
}
}
else if (puzzle.patterns == 0)
fprintf(f, ": No solutions\n\n");
else
{
fprintf(f, ": %s in %s\n\n",
PrintNumber(puzzle.count, true, "solution", "solutions").val(),
PrintNumber(puzzle.patterns, false, "pattern", "patterns").val());
if (puzzle.count1 + puzzle.count2 + puzzle.count4 == 1)
{
if (puzzle.count1 == 1)
fprintf(f, "The one solution is symmetric in two directions.\n");
else if (puzzle.count2 == 1)
fprintf(f, "The one normalized solution is symmetric in one direction.\n");
else
fprintf(f, "The one normalized solution is not symmetric in any direction.\n");
}
else
{
if (puzzle.count1 > 0)
fprintf(f, "%s symmetric in two directions.\n", PrintNumber(puzzle.count1, true, "normalized solution is", "normalized solutions are").val());
if (puzzle.count2 > 0)
fprintf(f, "%s symmetric in one direction.\n", PrintNumber(puzzle.count2, true, "normalized solution is", "normalized solutions are").val());
if (puzzle.count4 > 0)
fprintf(f, "%s not symmetric in any direction.\n", PrintNumber(puzzle.count4, true, "normalized solution is", "normalized solutions are").val());
}
int pieces_bv = puzzle.pieces_bv;
Puzzle* parts[7];
search_combined(puzzle.pieces_bv, width, 0, parts, puzzle);
long long nr_comb = 0;
long long comb_count = 0;
long long comb_norm_count = 0;
long long comb_pieces[7];
for (int i = 2; i < 7; i++)
comb_pieces[i] = 0;
for (Puzzle::CombinationIterator it(puzzle); it.more(); it.next())
{
nr_comb++;
comb_count += it.count();
comb_norm_count += it.norm_count();
comb_pieces[it.nr_parts()+1] += it.norm_count();
it.print(f);
}
puzzle.mix_count = puzzle.count - comb_count;
if (nr_comb == 1)
{
if (puzzle.mix_count == 0)
fprintf(f, "There are no mix solutions.\n");
else
fprintf(f, "This leaves %s.\n", PrintNumber(puzzle.mix_count, false, "mix solution","mix solutions").val());
}
else if (nr_comb > 1)
fprintf(f, "There are a total of %s (%s) that are permutations, leaving %s.\n",
PrintNumber(comb_count, false, "solution", "solutions").val(),
PrintNumber(comb_norm_count, false, "normalized solution", "normalized solutions").val(),
PrintNumber(puzzle.mix_count, false, "mix solution", "mix solutions").val());
int horz_split[10];
for (int i = 0; i < 10; i++)
horz_split[i] = 0;
for (Puzzle::LineIterator it(puzzle); it.more(); it.next())
{
int nr = 0;
for (int h = 1; h < width; h++)
{
bool split = true;
for (int v = 0; v < height; v++)
if (it.val()[v*width+h-1] == it.val()[v*width+h])
{
split = false;
break;
}
if (split)
nr++;
}
horz_split[nr]++;
}
if (horz_split[0] == 0)
{
int t = 0;
for (int i = 1; i < 10; i++)
if (horz_split[i] > 0)
t++;
if (t > 1)
fprintf(f, "All patterns are a combination of smaller patterns.\n");
}
bool some_split = false;
for (int i = 1; i < 10; i++)
if (horz_split[i] == puzzle.patterns)
fprintf(f, "All patterns are a combination of %s smaller patterns.\n", PrintNumber(i+1).val());
else if (horz_split[i] > 0)
{
fprintf(f, "%s a combination of %s smaller patterns.\n",
PrintNumber(horz_split[i], true, "pattern is", "patterns are").val(),
PrintNumber(i+1).val());
some_split = true;
}
if (puzzle.patterns > 1 && horz_split[0] > 0 && some_split)
fprintf(f, "%s a mix patterns.\n", PrintNumber(horz_split[0], true, "pattern is", "patterns are").val());
int factor = 8;
int total_height = 0;
for (; factor > 1; factor--)
{
total_height = factor*height;
int sx = 0;
for (Puzzle::LineIterator it(puzzle); it.more(); it.next())
{
sx++;
if (factor*((width+2)*sx + width) >= 600) { sx = 0; total_height += factor*(height+2); }
}
if (total_height <= 800)
break;
}
if (total_height <= 800)
{
print_min_max_neighbours(f, puzzle);
if (puzzle.patterns == 1)
fprintf(f, "The one pattern is:");
else
fprintf(f, "The patterns are:");
fprintf(f, "\n\n
\n");
fprintf(f, "\n");
}
else
{
int factor = 8;
int total_height = 0;
for (; factor > 1; factor--)
{
total_height = factor*height;
int sx = 0;
for (int i = 0; i < puzzle.nr_min_neighbours; i++)
{
sx++;
if (factor*((width+2)*sx + width) >= 600) { sx = 0; total_height += factor*(height+2); }
}
if (total_height <= 800)
break;
}
if (total_height <= 800)
{
fprintf(f, "Too many patterns to display them all.\n");
int diff = puzzle.min_neighbours - puzzle.abs_min_neighbours;
if (diff == 0)
fprintf(f, "The %s:",
PrintNumber(puzzle.nr_min_neighbours, false, "optimal minimal touching pattern is", "optimal minimal touching patterns are").val());
else
fprintf(f, "The %s suboptimal (%s extra) minimal touching %s:",
PrintNumber(puzzle.nr_min_neighbours).val(),
PrintNumber(diff).val(),
puzzle.nr_min_neighbours == 1 ? "pattern is" : "patterns are");
fprintf(f, "\n\n
\n");
fprintf(f, "\n");
}
else
{
fprintf(f, "Too many patterns to be displayed.\n");
print_min_max_neighbours(f, puzzle);
}
}
}
}
fprintf(f, "\n");
fprintf(f, "
\n");
fprintf(f, "\n");
fprintf(f, "Home and email\n");
fprintf(f, "| Chinese Wooden Puzzle\n");
fprintf(f, "\n");
fprintf(f, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
fprintf(f, "
\n");
fprintf(f, "\n");
}
int main(int argc, char *argv[])
{
if (argc > 1)
height = atoi(argv[1]);
multiplicity = height/2;
char infn[40];
sprintf(infn, "cwp_sols_%d.txt", multiplicity);
analyze(infn);
return 0;
}