puzzles: resync with upstream
This brings the puzzles source to upstream commit e2135d5. (I've made my own changes on top of that.) This brings in a couple bugfixes and a new solver for Dominosa. Change-Id: I11d46b43171787832330a5e2e0d2f353f36f727d
This commit is contained in:
parent
4ed5727654
commit
f940276fd9
11 changed files with 2533 additions and 504 deletions
|
@ -19,6 +19,7 @@ src/misc.c
|
||||||
src/penrose.c
|
src/penrose.c
|
||||||
src/printing.c
|
src/printing.c
|
||||||
src/random.c
|
src/random.c
|
||||||
|
src/sort.c
|
||||||
src/tdq.c
|
src/tdq.c
|
||||||
src/tree234.c
|
src/tree234.c
|
||||||
src/version.c
|
src/version.c
|
||||||
|
|
|
@ -9,7 +9,7 @@ my @presets = ();
|
||||||
my %presets = ();
|
my %presets = ();
|
||||||
my $maxval = 0;
|
my $maxval = 0;
|
||||||
|
|
||||||
while (<>) {
|
while (<<>>) {
|
||||||
chomp;
|
chomp;
|
||||||
if (/^(.*)(#.*): ([\d\.]+)$/) {
|
if (/^(.*)(#.*): ([\d\.]+)$/) {
|
||||||
push @presets, $1 unless defined $presets{$1};
|
push @presets, $1 unless defined $presets{$1};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# -*- makefile -*-
|
# -*- makefile -*-
|
||||||
|
|
||||||
DOMINOSA_EXTRA = laydomino
|
DOMINOSA_EXTRA = laydomino dsf sort findloop
|
||||||
|
|
||||||
dominosa : [X] GTK COMMON dominosa DOMINOSA_EXTRA dominosa-icon|no-icon
|
dominosa : [X] GTK COMMON dominosa DOMINOSA_EXTRA dominosa-icon|no-icon
|
||||||
|
|
||||||
|
@ -8,6 +8,9 @@ dominosa : [G] WINDOWS COMMON dominosa DOMINOSA_EXTRA dominosa.res|noicon.res
|
||||||
|
|
||||||
ALL += dominosa[COMBINED] DOMINOSA_EXTRA
|
ALL += dominosa[COMBINED] DOMINOSA_EXTRA
|
||||||
|
|
||||||
|
dominosasolver : [U] dominosa[STANDALONE_SOLVER] DOMINOSA_EXTRA STANDALONE
|
||||||
|
dominosasolver : [C] dominosa[STANDALONE_SOLVER] DOMINOSA_EXTRA STANDALONE
|
||||||
|
|
||||||
!begin am gtk
|
!begin am gtk
|
||||||
GAMES += dominosa
|
GAMES += dominosa
|
||||||
!end
|
!end
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -212,28 +212,51 @@ function initPuzzle() {
|
||||||
// button down (our puzzles don't want those events).
|
// button down (our puzzles don't want those events).
|
||||||
mousedown = Module.cwrap('mousedown', 'void',
|
mousedown = Module.cwrap('mousedown', 'void',
|
||||||
['number', 'number', 'number']);
|
['number', 'number', 'number']);
|
||||||
buttons_down = 0;
|
|
||||||
|
button_phys2log = [null, null, null];
|
||||||
|
buttons_down = function() {
|
||||||
|
var i, toret = 0;
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
if (button_phys2log[i] !== null)
|
||||||
|
toret |= 1 << button_phys2log[i];
|
||||||
|
return toret;
|
||||||
|
};
|
||||||
|
|
||||||
onscreen_canvas.onmousedown = function(event) {
|
onscreen_canvas.onmousedown = function(event) {
|
||||||
|
if (event.button >= 3)
|
||||||
|
return;
|
||||||
|
|
||||||
var xy = relative_mouse_coords(event, onscreen_canvas);
|
var xy = relative_mouse_coords(event, onscreen_canvas);
|
||||||
mousedown(xy.x, xy.y, event.button);
|
var logbutton = event.button;
|
||||||
buttons_down |= 1 << event.button;
|
if (event.shiftKey)
|
||||||
|
logbutton = 1; // Shift-click overrides to middle button
|
||||||
|
else if (event.ctrlKey)
|
||||||
|
logbutton = 2; // Ctrl-click overrides to right button
|
||||||
|
|
||||||
|
mousedown(xy.x, xy.y, logbutton);
|
||||||
|
button_phys2log[event.button] = logbutton;
|
||||||
|
|
||||||
onscreen_canvas.setCapture(true);
|
onscreen_canvas.setCapture(true);
|
||||||
};
|
};
|
||||||
mousemove = Module.cwrap('mousemove', 'void',
|
mousemove = Module.cwrap('mousemove', 'void',
|
||||||
['number', 'number', 'number']);
|
['number', 'number', 'number']);
|
||||||
onscreen_canvas.onmousemove = function(event) {
|
onscreen_canvas.onmousemove = function(event) {
|
||||||
if (buttons_down) {
|
var down = buttons_down();
|
||||||
|
if (down) {
|
||||||
var xy = relative_mouse_coords(event, onscreen_canvas);
|
var xy = relative_mouse_coords(event, onscreen_canvas);
|
||||||
mousemove(xy.x, xy.y, buttons_down);
|
mousemove(xy.x, xy.y, down);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mouseup = Module.cwrap('mouseup', 'void',
|
mouseup = Module.cwrap('mouseup', 'void',
|
||||||
['number', 'number', 'number']);
|
['number', 'number', 'number']);
|
||||||
onscreen_canvas.onmouseup = function(event) {
|
onscreen_canvas.onmouseup = function(event) {
|
||||||
if (buttons_down & (1 << event.button)) {
|
if (event.button >= 3)
|
||||||
buttons_down ^= 1 << event.button;
|
return;
|
||||||
|
|
||||||
|
if (button_phys2log[event.button] !== null) {
|
||||||
var xy = relative_mouse_coords(event, onscreen_canvas);
|
var xy = relative_mouse_coords(event, onscreen_canvas);
|
||||||
mouseup(xy.x, xy.y, event.button);
|
mouseup(xy.x, xy.y, button_phys2log[event.button]);
|
||||||
|
button_phys2log[event.button] = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include "puzzles.h"
|
#include "puzzles.h"
|
||||||
|
|
||||||
struct findloopstate {
|
struct findloopstate {
|
||||||
int parent, child, sibling;
|
int parent, child, sibling, component_root;
|
||||||
bool visited;
|
bool visited;
|
||||||
int index, minindex, maxindex;
|
int index, minindex, maxindex;
|
||||||
int minreachable, maxreachable;
|
int minreachable, maxreachable;
|
||||||
|
@ -57,6 +57,33 @@ bool findloop_is_loop_edge(struct findloopstate *pv, int u, int v)
|
||||||
return !(pv[u].bridge == v || pv[v].bridge == u);
|
return !(pv[u].bridge == v || pv[v].bridge == u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool findloop_is_bridge_oneway(
|
||||||
|
struct findloopstate *pv, int u, int v, int *u_vertices, int *v_vertices)
|
||||||
|
{
|
||||||
|
int r, total, below;
|
||||||
|
|
||||||
|
if (pv[u].bridge != v)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
r = pv[u].component_root;
|
||||||
|
total = pv[r].maxindex - pv[r].minindex + 1;
|
||||||
|
below = pv[u].maxindex - pv[u].minindex + 1;
|
||||||
|
|
||||||
|
if (u_vertices)
|
||||||
|
*u_vertices = below;
|
||||||
|
if (v_vertices)
|
||||||
|
*v_vertices = total - below;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool findloop_is_bridge(
|
||||||
|
struct findloopstate *pv, int u, int v, int *u_vertices, int *v_vertices)
|
||||||
|
{
|
||||||
|
return (findloop_is_bridge_oneway(pv, u, v, u_vertices, v_vertices) ||
|
||||||
|
findloop_is_bridge_oneway(pv, v, u, v_vertices, u_vertices));
|
||||||
|
}
|
||||||
|
|
||||||
bool findloop_run(struct findloopstate *pv, int nvertices,
|
bool findloop_run(struct findloopstate *pv, int nvertices,
|
||||||
neighbour_fn_t neighbour, void *ctx)
|
neighbour_fn_t neighbour, void *ctx)
|
||||||
{
|
{
|
||||||
|
@ -94,6 +121,7 @@ bool findloop_run(struct findloopstate *pv, int nvertices,
|
||||||
*/
|
*/
|
||||||
pv[v].sibling = pv[root].child;
|
pv[v].sibling = pv[root].child;
|
||||||
pv[root].child = v;
|
pv[root].child = v;
|
||||||
|
pv[v].component_root = v;
|
||||||
debug(("%d is new child of root\n", v));
|
debug(("%d is new child of root\n", v));
|
||||||
|
|
||||||
u = v;
|
u = v;
|
||||||
|
@ -116,6 +144,7 @@ bool findloop_run(struct findloopstate *pv, int nvertices,
|
||||||
pv[w].child = -1;
|
pv[w].child = -1;
|
||||||
pv[w].sibling = pv[u].child;
|
pv[w].sibling = pv[u].child;
|
||||||
pv[w].parent = u;
|
pv[w].parent = u;
|
||||||
|
pv[w].component_root = pv[u].component_root;
|
||||||
pv[u].child = w;
|
pv[u].child = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -346,29 +346,44 @@ static void add_assoc(const game_state *state, space *tile, space *dot) {
|
||||||
tile->x, tile->y, dot->x, dot->y, dot->nassoc));*/
|
tile->x, tile->y, dot->x, dot->y, dot->nassoc));*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_assoc_with_opposite(game_state *state, space *tile, space *dot) {
|
static bool ok_to_add_assoc_with_opposite_internal(
|
||||||
|
const game_state *state, space *tile, space *opposite)
|
||||||
|
{
|
||||||
int *colors;
|
int *colors;
|
||||||
space *opposite = space_opposite_dot(state, tile, dot);
|
bool toret;
|
||||||
|
|
||||||
if (opposite == NULL) {
|
if (tile->flags & F_DOT)
|
||||||
return;
|
return false;
|
||||||
}
|
if (opposite == NULL)
|
||||||
if (opposite->flags & F_DOT) {
|
return false;
|
||||||
return;
|
if (opposite->flags & F_DOT)
|
||||||
}
|
return false;
|
||||||
|
|
||||||
|
toret = true;
|
||||||
colors = snewn(state->w * state->h, int);
|
colors = snewn(state->w * state->h, int);
|
||||||
check_complete(state, NULL, colors);
|
check_complete(state, NULL, colors);
|
||||||
if (colors[(tile->y - 1)/2 * state->w + (tile->x - 1)/2]) {
|
|
||||||
sfree(colors);
|
if (colors[(tile->y - 1)/2 * state->w + (tile->x - 1)/2])
|
||||||
return;
|
toret = false;
|
||||||
}
|
if (colors[(opposite->y - 1)/2 * state->w + (opposite->x - 1)/2])
|
||||||
if (colors[(opposite->y - 1)/2 * state->w + (opposite->x - 1)/2]) {
|
toret = false;
|
||||||
sfree(colors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sfree(colors);
|
sfree(colors);
|
||||||
|
return toret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ok_to_add_assoc_with_opposite(
|
||||||
|
const game_state *state, space *tile, space *dot)
|
||||||
|
{
|
||||||
|
space *opposite = space_opposite_dot(state, tile, dot);
|
||||||
|
return ok_to_add_assoc_with_opposite_internal(state, tile, opposite);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_assoc_with_opposite(game_state *state, space *tile, space *dot) {
|
||||||
|
space *opposite = space_opposite_dot(state, tile, dot);
|
||||||
|
|
||||||
|
assert(ok_to_add_assoc_with_opposite_internal(state, tile, opposite));
|
||||||
|
|
||||||
remove_assoc_with_opposite(state, tile);
|
remove_assoc_with_opposite(state, tile);
|
||||||
add_assoc(state, tile, dot);
|
add_assoc(state, tile, dot);
|
||||||
remove_assoc_with_opposite(state, opposite);
|
remove_assoc_with_opposite(state, opposite);
|
||||||
|
@ -2596,8 +2611,15 @@ static char *interpret_move(const game_state *state, game_ui *ui,
|
||||||
*/
|
*/
|
||||||
if (INUI(state, px, py)) {
|
if (INUI(state, px, py)) {
|
||||||
sp = &SPACE(state, px, py);
|
sp = &SPACE(state, px, py);
|
||||||
|
dot = &SPACE(state, ui->dotx, ui->doty);
|
||||||
|
|
||||||
if (!(sp->flags & F_DOT))
|
/*
|
||||||
|
* Exception: if it's not actually legal to add an arrow
|
||||||
|
* and its opposite at this position, we don't try,
|
||||||
|
* because otherwise we'd append an empty entry to the
|
||||||
|
* undo chain.
|
||||||
|
*/
|
||||||
|
if (ok_to_add_assoc_with_opposite(state, sp, dot))
|
||||||
sprintf(buf + strlen(buf), "%sA%d,%d,%d,%d",
|
sprintf(buf + strlen(buf), "%sA%d,%d,%d,%d",
|
||||||
sep, px, py, ui->dotx, ui->doty);
|
sep, px, py, ui->dotx, ui->doty);
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,6 +171,8 @@ midend *midend_new(frontend *fe, const game *ourgame,
|
||||||
me->params = ourgame->default_params();
|
me->params = ourgame->default_params();
|
||||||
me->game_id_change_notify_function = NULL;
|
me->game_id_change_notify_function = NULL;
|
||||||
me->game_id_change_notify_ctx = NULL;
|
me->game_id_change_notify_ctx = NULL;
|
||||||
|
me->encoded_presets = NULL;
|
||||||
|
me->n_encoded_presets = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allow environment-based changing of the default settings by
|
* Allow environment-based changing of the default settings by
|
||||||
|
@ -261,8 +263,13 @@ static void midend_free_preset_menu(midend *me, struct preset_menu *menu)
|
||||||
|
|
||||||
void midend_free(midend *me)
|
void midend_free(midend *me)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
midend_free_game(me);
|
midend_free_game(me);
|
||||||
|
|
||||||
|
for (i = 0; i < me->n_encoded_presets; i++)
|
||||||
|
sfree(me->encoded_presets[i]);
|
||||||
|
sfree(me->encoded_presets);
|
||||||
if (me->drawing)
|
if (me->drawing)
|
||||||
drawing_free(me->drawing);
|
drawing_free(me->drawing);
|
||||||
random_free(me->random);
|
random_free(me->random);
|
||||||
|
|
|
@ -792,6 +792,12 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
|
||||||
* unoccupied.
|
* unoccupied.
|
||||||
*/
|
*/
|
||||||
ui->dragging = false;
|
ui->dragging = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Also, cancel a keyboard-driven jump if one is half way to being
|
||||||
|
* input.
|
||||||
|
*/
|
||||||
|
ui->cur_jumping = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PREFERRED_TILE_SIZE 33
|
#define PREFERRED_TILE_SIZE 33
|
||||||
|
|
|
@ -594,6 +594,32 @@ bool findloop_run(struct findloopstate *state, int nvertices,
|
||||||
*/
|
*/
|
||||||
bool findloop_is_loop_edge(struct findloopstate *state, int u, int v);
|
bool findloop_is_loop_edge(struct findloopstate *state, int u, int v);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Alternative query function, which returns true if the u-v edge is a
|
||||||
|
* _bridge_, i.e. a non-loop edge, i.e. an edge whose removal would
|
||||||
|
* disconnect a currently connected component of the graph.
|
||||||
|
*
|
||||||
|
* If the return value is true, then the numbers of vertices that
|
||||||
|
* would be in the new components containing u and v are written into
|
||||||
|
* u_vertices and v_vertices respectively.
|
||||||
|
*/
|
||||||
|
bool findloop_is_bridge(
|
||||||
|
struct findloopstate *pv, int u, int v, int *u_vertices, int *v_vertices);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper function to sort an array. Differs from standard qsort in
|
||||||
|
* that it takes a context parameter that is passed to the compare
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* I wrap it in a macro so that you only need to give the element
|
||||||
|
* count of the array. The element size is determined by sizeof.
|
||||||
|
*/
|
||||||
|
typedef int (*arraysort_cmpfn_t)(const void *av, const void *bv, void *ctx);
|
||||||
|
void arraysort_fn(void *array, size_t nmemb, size_t size,
|
||||||
|
arraysort_cmpfn_t cmp, void *ctx);
|
||||||
|
#define arraysort(array, nmemb, cmp, ctx) \
|
||||||
|
arraysort_fn(array, nmemb, sizeof(*(array)), cmp, ctx)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Data structure containing the function calls and data specific
|
* Data structure containing the function calls and data specific
|
||||||
* to a particular game. This is enclosed in a data structure so
|
* to a particular game. This is enclosed in a data structure so
|
||||||
|
|
160
apps/plugins/puzzles/src/sort.c
Normal file
160
apps/plugins/puzzles/src/sort.c
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
/*
|
||||||
|
* Implement arraysort() defined in puzzles.h.
|
||||||
|
*
|
||||||
|
* Strategy: heapsort.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "puzzles.h"
|
||||||
|
|
||||||
|
static void memswap(void *av, void *bv, size_t size)
|
||||||
|
{
|
||||||
|
char t[4096];
|
||||||
|
char *a = (char *)av, *b = (char *)bv;
|
||||||
|
|
||||||
|
while (size > 0) {
|
||||||
|
size_t thissize = size < sizeof(t) ? size : sizeof(t);
|
||||||
|
|
||||||
|
memcpy(t, a, thissize);
|
||||||
|
memcpy(a, b, thissize);
|
||||||
|
memcpy(b, t, thissize);
|
||||||
|
|
||||||
|
size -= thissize;
|
||||||
|
a += thissize;
|
||||||
|
b += thissize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PTR(i) ((char *)array + size * (i))
|
||||||
|
#define SWAP(i,j) memswap(PTR(i), PTR(j), size)
|
||||||
|
#define CMP(i,j) cmp(PTR(i), PTR(j), ctx)
|
||||||
|
|
||||||
|
#define LCHILD(i) (2*(i)+1)
|
||||||
|
#define RCHILD(i) (2*(i)+2)
|
||||||
|
#define PARENT(i) (((i)-1)/2)
|
||||||
|
|
||||||
|
static void downheap(void *array, size_t nmemb, size_t size,
|
||||||
|
arraysort_cmpfn_t cmp, void *ctx, size_t i)
|
||||||
|
{
|
||||||
|
while (LCHILD(i) < nmemb) {
|
||||||
|
/* Identify the smallest element out of i and its children. */
|
||||||
|
size_t j = i;
|
||||||
|
if (CMP(j, LCHILD(i)) < 0)
|
||||||
|
j = LCHILD(i);
|
||||||
|
if (RCHILD(i) < nmemb &&
|
||||||
|
CMP(j, RCHILD(i)) < 0)
|
||||||
|
j = RCHILD(i);
|
||||||
|
|
||||||
|
if (j == i)
|
||||||
|
return; /* smallest element is already where it should be */
|
||||||
|
|
||||||
|
SWAP(j, i);
|
||||||
|
i = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void arraysort_fn(void *array, size_t nmemb, size_t size,
|
||||||
|
arraysort_cmpfn_t cmp, void *ctx)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (nmemb < 2)
|
||||||
|
return; /* trivial */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stage 1: build the heap.
|
||||||
|
*
|
||||||
|
* Linear-time if we do it by downheaping the elements in
|
||||||
|
* decreasing order of index, instead of the more obvious approach
|
||||||
|
* of upheaping in increasing order. (Also, it means we don't need
|
||||||
|
* the upheap function at all.)
|
||||||
|
*
|
||||||
|
* We don't need to downheap anything in the second half of the
|
||||||
|
* array, because it can't have any children to swap with anyway.
|
||||||
|
*/
|
||||||
|
for (i = PARENT(nmemb-1) + 1; i-- > 0 ;)
|
||||||
|
downheap(array, nmemb, size, cmp, ctx, i);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stage 2: dismantle the heap by repeatedly swapping the root
|
||||||
|
* element (at index 0) into the last position and then
|
||||||
|
* downheaping the new root.
|
||||||
|
*/
|
||||||
|
for (i = nmemb-1; i > 0; i--) {
|
||||||
|
SWAP(0, i);
|
||||||
|
downheap(array, i, size, cmp, ctx, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SORT_TEST
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
int testcmp(const void *av, const void *bv, void *ctx)
|
||||||
|
{
|
||||||
|
int a = *(const int *)av, b = *(const int *)bv;
|
||||||
|
const int *keys = (const int *)ctx;
|
||||||
|
return keys[a] < keys[b] ? -1 : keys[a] > keys[b] ? +1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resetcmp(const void *av, const void *bv)
|
||||||
|
{
|
||||||
|
int a = *(const int *)av, b = *(const int *)bv;
|
||||||
|
return a < b ? -1 : a > b ? +1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
typedef int Array[3723];
|
||||||
|
Array data, keys;
|
||||||
|
int iteration;
|
||||||
|
unsigned seed;
|
||||||
|
|
||||||
|
seed = (argc > 1 ? strtoul(argv[1], NULL, 0) : time(NULL));
|
||||||
|
printf("Random seed = %u\n", seed);
|
||||||
|
srand(seed);
|
||||||
|
|
||||||
|
for (iteration = 0; iteration < 10000; iteration++) {
|
||||||
|
int j;
|
||||||
|
const char *fail = NULL;
|
||||||
|
|
||||||
|
for (j = 0; j < lenof(data); j++) {
|
||||||
|
data[j] = j;
|
||||||
|
keys[j] = rand();
|
||||||
|
}
|
||||||
|
|
||||||
|
arraysort(data, lenof(data), testcmp, keys);
|
||||||
|
|
||||||
|
for (j = 1; j < lenof(data); j++) {
|
||||||
|
if (keys[data[j]] < keys[data[j-1]])
|
||||||
|
fail = "output misordered";
|
||||||
|
}
|
||||||
|
if (!fail) {
|
||||||
|
Array reset;
|
||||||
|
memcpy(reset, data, sizeof(data));
|
||||||
|
qsort(reset, lenof(reset), sizeof(*reset), resetcmp);
|
||||||
|
for (j = 0; j < lenof(reset); j++)
|
||||||
|
if (reset[j] != j)
|
||||||
|
fail = "output not permuted";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fail) {
|
||||||
|
printf("Failed at iteration %d: %s\n", iteration, fail);
|
||||||
|
printf("Key values:\n");
|
||||||
|
for (j = 0; j < lenof(keys); j++)
|
||||||
|
printf(" [%2d] %10d\n", j, keys[j]);
|
||||||
|
printf("Output sorted order:\n");
|
||||||
|
for (j = 0; j < lenof(data); j++)
|
||||||
|
printf(" [%2d] %10d\n", data[j], keys[data[j]]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("OK\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SORT_TEST */
|
Loading…
Reference in a new issue