mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 08:01:30 -07:00
Mike Pinna has done some major reworking of the Loopy solver, giving
rise to a new Hard difficulty level. [originally from svn r6880]
This commit is contained in:
152
dsf.c
152
dsf.c
@ -1,38 +1,156 @@
|
|||||||
/*
|
/*
|
||||||
* dsf.c: two small functions to handle a disjoint set forest,
|
* dsf.c: some functions to handle a disjoint set forest,
|
||||||
* which is a data structure useful in any solver which has to
|
* which is a data structure useful in any solver which has to
|
||||||
* worry about avoiding closed loops.
|
* worry about avoiding closed loops.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "puzzles.h"
|
#include "puzzles.h"
|
||||||
|
|
||||||
int dsf_canonify(int *dsf, int val)
|
void print_dsf(int *dsf, int size)
|
||||||
{
|
{
|
||||||
int v2 = val;
|
int *printed_elements = snewn(size, int);
|
||||||
|
int *equal_elements = snewn(size, int);
|
||||||
|
int *inverse_elements = snewn(size, int);
|
||||||
|
int printed_count = 0, equal_count, inverse_count;
|
||||||
|
int i, n, inverse;
|
||||||
|
|
||||||
while (dsf[val] != val)
|
memset(printed_elements, -1, sizeof(int) * size);
|
||||||
val = dsf[val];
|
|
||||||
|
|
||||||
while (v2 != val) {
|
while (1) {
|
||||||
int tmp = dsf[v2];
|
equal_count = 0;
|
||||||
dsf[v2] = val;
|
inverse_count = 0;
|
||||||
v2 = tmp;
|
for (i = 0; i < size; ++i) {
|
||||||
|
if (!memchr(printed_elements, i, sizeof(int) * size))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == size)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
i = dsf_canonify(dsf, i);
|
||||||
|
|
||||||
|
for (n = 0; n < size; ++n) {
|
||||||
|
if (edsf_canonify(dsf, n, &inverse) == i) {
|
||||||
|
if (inverse)
|
||||||
|
inverse_elements[inverse_count++] = n;
|
||||||
|
else
|
||||||
|
equal_elements[equal_count++] = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n = 0; n < equal_count; ++n) {
|
||||||
|
fprintf(stderr, "%d ", equal_elements[n]);
|
||||||
|
printed_elements[printed_count++] = equal_elements[n];
|
||||||
|
}
|
||||||
|
if (inverse_count) {
|
||||||
|
fprintf(stderr, "!= ");
|
||||||
|
for (n = 0; n < inverse_count; ++n) {
|
||||||
|
fprintf(stderr, "%d ", inverse_elements[n]);
|
||||||
|
printed_elements[printed_count++] = inverse_elements[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
|
||||||
|
sfree(printed_elements);
|
||||||
|
sfree(equal_elements);
|
||||||
|
sfree(inverse_elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
int *snew_dsf(int size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int *ret;
|
||||||
|
|
||||||
|
ret = snewn(size, int);
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
/* Bottom bit of each element of this array stores whether that element
|
||||||
|
* is opposite to its parent, which starts off as false */
|
||||||
|
ret[i] = i << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return val;
|
/*print_dsf(ret, size); */
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dsf_canonify(int *dsf, int index)
|
||||||
|
{
|
||||||
|
return edsf_canonify(dsf, index, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsf_merge(int *dsf, int v1, int v2)
|
void dsf_merge(int *dsf, int v1, int v2)
|
||||||
{
|
{
|
||||||
v1 = dsf_canonify(dsf, v1);
|
edsf_merge(dsf, v1, v2, FALSE);
|
||||||
v2 = dsf_canonify(dsf, v2);
|
|
||||||
dsf[v2] = v1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsf_init(int *dsf, int len)
|
int edsf_canonify(int *dsf, int index, int *inverse_return)
|
||||||
{
|
{
|
||||||
int i;
|
int start_index = index, canonical_index;
|
||||||
|
int inverse = 0;
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
/* fprintf(stderr, "dsf = %p\n", dsf); */
|
||||||
dsf[i] = i;
|
/* fprintf(stderr, "Canonify %2d\n", index); */
|
||||||
|
|
||||||
|
assert(index >= 0);
|
||||||
|
|
||||||
|
/* Find the index of the canonical element of the 'equivalence class' of
|
||||||
|
* which start_index is a member, and figure out whether start_index is the
|
||||||
|
* same as or inverse to that. */
|
||||||
|
while ((dsf[index] >> 1) != index) {
|
||||||
|
inverse ^= (dsf[index] & 1);
|
||||||
|
index = dsf[index] >> 1;
|
||||||
|
/* fprintf(stderr, "index = %2d, ", index); */
|
||||||
|
/* fprintf(stderr, "inverse = %d\n", inverse); */
|
||||||
|
}
|
||||||
|
canonical_index = index;
|
||||||
|
|
||||||
|
if (inverse_return)
|
||||||
|
*inverse_return = inverse;
|
||||||
|
|
||||||
|
/* Update every member of this 'equivalence class' to point directly at the
|
||||||
|
* canonical member. */
|
||||||
|
index = start_index;
|
||||||
|
while (index != canonical_index) {
|
||||||
|
int nextindex = dsf[index] >> 1;
|
||||||
|
int nextinverse = inverse ^ (dsf[index] & 1);
|
||||||
|
dsf[index] = (canonical_index << 1) | inverse;
|
||||||
|
inverse = nextinverse;
|
||||||
|
index = nextindex;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(inverse == 0);
|
||||||
|
|
||||||
|
/* fprintf(stderr, "Return %2d\n", index); */
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void edsf_merge(int *dsf, int v1, int v2, int inverse)
|
||||||
|
{
|
||||||
|
int i1, i2;
|
||||||
|
|
||||||
|
/* fprintf(stderr, "dsf = %p\n", dsf); */
|
||||||
|
/* fprintf(stderr, "Merge [%2d,%2d], %d\n", v1, v2, inverse); */
|
||||||
|
|
||||||
|
v1 = edsf_canonify(dsf, v1, &i1);
|
||||||
|
inverse ^= i1;
|
||||||
|
v2 = edsf_canonify(dsf, v2, &i2);
|
||||||
|
inverse ^= i2;
|
||||||
|
|
||||||
|
/* fprintf(stderr, "Doing [%2d,%2d], %d\n", v1, v2, inverse); */
|
||||||
|
|
||||||
|
if (v1 == v2)
|
||||||
|
assert(!inverse);
|
||||||
|
else
|
||||||
|
dsf[v2] = (v1 << 1) | !!inverse;
|
||||||
|
|
||||||
|
v2 = edsf_canonify(dsf, v2, &i2);
|
||||||
|
assert(v2 == v1);
|
||||||
|
assert(i2 == inverse);
|
||||||
|
|
||||||
|
/* fprintf(stderr, "dsf[%2d] = %2d\n", v2, dsf[v2]); */
|
||||||
}
|
}
|
||||||
|
15
puzzles.h
15
puzzles.h
@ -278,7 +278,22 @@ void draw_rect_outline(drawing *dr, int x, int y, int w, int h,
|
|||||||
/*
|
/*
|
||||||
* dsf.c
|
* dsf.c
|
||||||
*/
|
*/
|
||||||
|
int *snew_dsf(int size);
|
||||||
|
|
||||||
|
void print_dsf(int *dsf, int size);
|
||||||
|
|
||||||
|
/* Return the canonical element of the equivalence class containing element
|
||||||
|
* val. If 'inverse' is non-NULL, this function will put into it a flag
|
||||||
|
* indicating whether the canonical element is inverse to val. */
|
||||||
|
int edsf_canonify(int *dsf, int val, int *inverse);
|
||||||
int dsf_canonify(int *dsf, int val);
|
int dsf_canonify(int *dsf, int val);
|
||||||
|
|
||||||
|
/* Allow the caller to specify that two elements should be in the same
|
||||||
|
* equivalence class. If 'inverse' is TRUE, the elements are actually opposite
|
||||||
|
* to one another in some sense. This function will fail an assertion if the
|
||||||
|
* caller gives it self-contradictory data, ie if two elements are claimed to
|
||||||
|
* be both opposite and non-opposite. */
|
||||||
|
void edsf_merge(int *dsf, int v1, int v2, int inverse);
|
||||||
void dsf_merge(int *dsf, int v1, int v2);
|
void dsf_merge(int *dsf, int v1, int v2);
|
||||||
void dsf_init(int *dsf, int len);
|
void dsf_init(int *dsf, int len);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user