mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 08:01:30 -07:00
Apply some optimisation to Undead's get_unique() function, which was
not only enumerating all possible arrangements of monsters along a sight-line in O(3^n) time, but also allocated memory for them all and then does a quadratic-time loop over that list to find arrangements with a unique visibility count from both ends. Spotted by the new 'make test', which observed that 7x7dn#517035041807425 took 45 seconds to generate. This revised version still does the initial O(3^n) enumeration, which can probably be got rid of as well with a bit more thought, but it now doesn't allocate nearly so much memory and it spots uniques efficiently. The above random seed now generates the same game ID in less than a second, which drops this puzzle off the 'make test' hit list of things most obviously needing speedup. [originally from svn r9826]
This commit is contained in:
65
undead.c
65
undead.c
@ -576,8 +576,9 @@ int next_list(struct guess *g, int pos) {
|
|||||||
|
|
||||||
void get_unique(game_state *state, int counter, random_state *rs) {
|
void get_unique(game_state *state, int counter, random_state *rs) {
|
||||||
|
|
||||||
int p,i,c,count_uniques;
|
int p,i,c,pathlimit,count_uniques;
|
||||||
struct guess path_guess;
|
struct guess path_guess;
|
||||||
|
int *view_count;
|
||||||
|
|
||||||
struct entry {
|
struct entry {
|
||||||
struct entry *link;
|
struct entry *link;
|
||||||
@ -589,7 +590,7 @@ void get_unique(game_state *state, int counter, random_state *rs) {
|
|||||||
struct {
|
struct {
|
||||||
struct entry *head;
|
struct entry *head;
|
||||||
struct entry *node;
|
struct entry *node;
|
||||||
} views, single_views, loop_views, test_views;
|
} views, single_views, test_views;
|
||||||
|
|
||||||
struct entry test_entry;
|
struct entry test_entry;
|
||||||
|
|
||||||
@ -616,19 +617,16 @@ void get_unique(game_state *state, int counter, random_state *rs) {
|
|||||||
views.head = NULL;
|
views.head = NULL;
|
||||||
views.node = NULL;
|
views.node = NULL;
|
||||||
|
|
||||||
do {
|
pathlimit = state->common->paths[counter].length + 1;
|
||||||
int mirror;
|
view_count = snewn(pathlimit*pathlimit, int);
|
||||||
|
for (i = 0; i < pathlimit*pathlimit; i++)
|
||||||
|
view_count[i] = 0;
|
||||||
|
|
||||||
views.node = snewn(1,struct entry);
|
do {
|
||||||
views.node->link = views.head;
|
int mirror, start_view, end_view;
|
||||||
views.node->guess = snewn(path_guess.length,int);
|
|
||||||
views.head = views.node;
|
|
||||||
views.node->start_view = 0;
|
|
||||||
views.node->end_view = 0;
|
|
||||||
memcpy(views.node->guess, path_guess.guess,
|
|
||||||
path_guess.length*sizeof(int));
|
|
||||||
|
|
||||||
mirror = FALSE;
|
mirror = FALSE;
|
||||||
|
start_view = 0;
|
||||||
for (p=0;p<state->common->paths[counter].length;p++) {
|
for (p=0;p<state->common->paths[counter].length;p++) {
|
||||||
if (state->common->paths[counter].p[p] == -1) mirror = TRUE;
|
if (state->common->paths[counter].p[p] == -1) mirror = TRUE;
|
||||||
else {
|
else {
|
||||||
@ -636,17 +634,18 @@ void get_unique(game_state *state, int counter, random_state *rs) {
|
|||||||
if (state->common->paths[counter].p[p] ==
|
if (state->common->paths[counter].p[p] ==
|
||||||
state->common->paths[counter].mapping[i]) {
|
state->common->paths[counter].mapping[i]) {
|
||||||
if (path_guess.guess[i] == 1 && mirror == TRUE)
|
if (path_guess.guess[i] == 1 && mirror == TRUE)
|
||||||
views.node->start_view++;
|
start_view++;
|
||||||
if (path_guess.guess[i] == 2 && mirror == FALSE)
|
if (path_guess.guess[i] == 2 && mirror == FALSE)
|
||||||
views.node->start_view++;
|
start_view++;
|
||||||
if (path_guess.guess[i] == 4)
|
if (path_guess.guess[i] == 4)
|
||||||
views.node->start_view++;
|
start_view++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mirror = FALSE;
|
mirror = FALSE;
|
||||||
|
end_view = 0;
|
||||||
for (p=state->common->paths[counter].length-1;p>=0;p--) {
|
for (p=state->common->paths[counter].length-1;p>=0;p--) {
|
||||||
if (state->common->paths[counter].p[p] == -1) mirror = TRUE;
|
if (state->common->paths[counter].p[p] == -1) mirror = TRUE;
|
||||||
else {
|
else {
|
||||||
@ -654,16 +653,31 @@ void get_unique(game_state *state, int counter, random_state *rs) {
|
|||||||
if (state->common->paths[counter].p[p] ==
|
if (state->common->paths[counter].p[p] ==
|
||||||
state->common->paths[counter].mapping[i]) {
|
state->common->paths[counter].mapping[i]) {
|
||||||
if (path_guess.guess[i] == 1 && mirror == TRUE)
|
if (path_guess.guess[i] == 1 && mirror == TRUE)
|
||||||
views.node->end_view++;
|
end_view++;
|
||||||
if (path_guess.guess[i] == 2 && mirror == FALSE)
|
if (path_guess.guess[i] == 2 && mirror == FALSE)
|
||||||
views.node->end_view++;
|
end_view++;
|
||||||
if (path_guess.guess[i] == 4)
|
if (path_guess.guess[i] == 4)
|
||||||
views.node->end_view++;
|
end_view++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(start_view >= 0 && start_view < pathlimit);
|
||||||
|
assert(end_view >= 0 && end_view < pathlimit);
|
||||||
|
i = start_view * pathlimit + end_view;
|
||||||
|
view_count[i]++;
|
||||||
|
if (view_count[i] == 1) {
|
||||||
|
views.node = snewn(1,struct entry);
|
||||||
|
views.node->link = views.head;
|
||||||
|
views.node->guess = snewn(path_guess.length,int);
|
||||||
|
views.head = views.node;
|
||||||
|
views.node->start_view = start_view;
|
||||||
|
views.node->end_view = end_view;
|
||||||
|
memcpy(views.node->guess, path_guess.guess,
|
||||||
|
path_guess.length*sizeof(int));
|
||||||
|
}
|
||||||
} while (next_list(&path_guess, path_guess.length-1));
|
} while (next_list(&path_guess, path_guess.length-1));
|
||||||
|
|
||||||
/* extract single entries from view list */
|
/* extract single entries from view list */
|
||||||
@ -680,17 +694,8 @@ void get_unique(game_state *state, int counter, random_state *rs) {
|
|||||||
while (test_views.head != NULL) {
|
while (test_views.head != NULL) {
|
||||||
test_views.node = test_views.head;
|
test_views.node = test_views.head;
|
||||||
test_views.head = test_views.head->link;
|
test_views.head = test_views.head->link;
|
||||||
c = 0;
|
i = test_views.node->start_view * pathlimit + test_views.node->end_view;
|
||||||
loop_views.head = views.head;
|
if (view_count[i] == 1) {
|
||||||
loop_views.node = views.node;
|
|
||||||
while (loop_views.head != NULL) {
|
|
||||||
loop_views.node = loop_views.head;
|
|
||||||
loop_views.head = loop_views.head->link;
|
|
||||||
if (test_views.node->start_view == loop_views.node->start_view &&
|
|
||||||
test_views.node->end_view == loop_views.node->end_view)
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
if (c == 1) {
|
|
||||||
single_views.node = snewn(1,struct entry);
|
single_views.node = snewn(1,struct entry);
|
||||||
single_views.node->link = single_views.head;
|
single_views.node->link = single_views.head;
|
||||||
single_views.node->guess = snewn(path_guess.length,int);
|
single_views.node->guess = snewn(path_guess.length,int);
|
||||||
@ -703,6 +708,8 @@ void get_unique(game_state *state, int counter, random_state *rs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sfree(view_count);
|
||||||
|
|
||||||
if (count_uniques > 0) {
|
if (count_uniques > 0) {
|
||||||
test_entry.start_view = 0;
|
test_entry.start_view = 0;
|
||||||
test_entry.end_view = 0;
|
test_entry.end_view = 0;
|
||||||
|
Reference in New Issue
Block a user