mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 08:01:30 -07:00
Update the documentation for the dsf functions.
Easier to do this all in one go after I've finished messing about.
This commit is contained in:
138
devel.but
138
devel.but
@ -4488,15 +4488,16 @@ practice. In particular, any time a dsf has to do non-trivial work, it
|
|||||||
updates the structure so that that work won't be needed a second time.
|
updates the structure so that that work won't be needed a second time.
|
||||||
Use dsf operations without worrying about how long they take!
|
Use dsf operations without worrying about how long they take!
|
||||||
|
|
||||||
These functions also support an \q{extended} version of a dsf (spelled
|
For some puzzle-game applications, it's useful to augment this data
|
||||||
\q{edsf}), in which each equivalence class is itself partitioned into
|
structure with extra information about how the elements of an
|
||||||
two sub-classes. When you merge two elements, you say whether they're
|
equivalence class relate to each other. There's more than one way you
|
||||||
in the same class or in opposite classes; when you test equivalence,
|
might do this; the one supported here is useful in cases where the
|
||||||
you can find out whether the two elements you're asking about are in
|
objects you're tracking are going to end up in one of two states (say,
|
||||||
the same or opposite classes. For example, in a puzzle containing
|
black/white, or on/off), and for any two objects you either know that
|
||||||
black and white squares, you might use an edsf to track the solver's
|
they're in the same one of those states, or you know they're in
|
||||||
knowledge about whether each pair of squares were (a) the same colour;
|
opposite states, or you don't know which yet. Puzzles calls this a
|
||||||
(b) opposite colours; (c) currently not known to be related.
|
\q{flip dsf}: it tracks whether objects in the same equivalence class
|
||||||
|
are flipped relative to each other.
|
||||||
|
|
||||||
As well as querying whether two elements are equivalent, this dsf
|
As well as querying whether two elements are equivalent, this dsf
|
||||||
implementation also allows you to ask for the number of elements in a
|
implementation also allows you to ask for the number of elements in a
|
||||||
@ -4504,41 +4505,67 @@ given equivalence class, and the smallest element in the class. (The
|
|||||||
latter is used, for example, to decide which square to print the clue
|
latter is used, for example, to decide which square to print the clue
|
||||||
in each region of a Keen puzzle.)
|
in each region of a Keen puzzle.)
|
||||||
|
|
||||||
\S{utils-dsf-new} \cw{snew_dsf()}
|
\S{utils-dsf-new} \cw{dsf_new()}, \cw{dsf_new_flip()}, \cw{dsf_new_min()}
|
||||||
|
|
||||||
\c int *snew_dsf(int size);
|
\c DSF *dsf_new(int size);
|
||||||
|
\c DSF *dsf_new_flip(int size);
|
||||||
|
\c DSF *dsf_new_min(int size);
|
||||||
|
|
||||||
Allocates space for a dsf describing \c{size} elements, and
|
Each of these functions allocates space for a dsf describing \c{size}
|
||||||
initialises it so that every element is in an equivalence class by
|
elements, and initialises it so that every element is in an
|
||||||
itself.
|
equivalence class by itself.
|
||||||
|
|
||||||
The elements described by the dsf are represented by the integers from
|
The elements described by the dsf are represented by the integers from
|
||||||
\cw{0} to \cw{size-1} inclusive.
|
\cw{0} to \cw{size-1} inclusive.
|
||||||
|
|
||||||
The returned memory is a single allocation, so you can free it easily
|
\cw{dsf_new_flip()} will create a dsf which has the extra ability to
|
||||||
using \cw{sfree()}.
|
track whether objects in the same equivalence class are flipped
|
||||||
|
relative to each other.
|
||||||
|
|
||||||
Dsfs and edsfs are represented in the same way, so this function can
|
\cw{dsf_new_min()} will create a dsf which has the extra ability to
|
||||||
be used to allocate either kind.
|
track the smallest element of each equivalence class.
|
||||||
|
|
||||||
\S{utils-dsf-init} \cw{dsf_init()}
|
The returned object from any of these functions must be freed using
|
||||||
|
\cw{dsf_free()}.
|
||||||
|
|
||||||
\c void dsf_init(int *dsf, int size);
|
\S{utils-dsf-free} \cw{dsf_free()}
|
||||||
|
|
||||||
|
\c void dsf_free(DSF *dsf);
|
||||||
|
|
||||||
|
Frees a dsf allocated by any of the \cw{dsf_new()} functions.
|
||||||
|
|
||||||
|
\S{utils-dsf-reinit} \cw{dsf_reinit()}
|
||||||
|
|
||||||
|
\c void dsf_reinit(DSF *dsf);
|
||||||
|
|
||||||
Reinitialises an existing dsf to the state in which all elements are
|
Reinitialises an existing dsf to the state in which all elements are
|
||||||
distinct, without having to free and reallocate it.
|
distinct, without having to free and reallocate it.
|
||||||
|
|
||||||
|
\S{utils-dsf-copy} \cw{dsf_copy()}
|
||||||
|
|
||||||
|
\c void dsf_copy(DSF *to, DSF *from);
|
||||||
|
|
||||||
|
Copies the contents of one dsf over the top of another. Everything
|
||||||
|
previously stored in \c{to} is overwritten.
|
||||||
|
|
||||||
|
The two dsfs must have been created with the same size, and the
|
||||||
|
destination dsf may not have any extra information that the source dsf
|
||||||
|
does not have.
|
||||||
|
|
||||||
\S{utils-dsf-merge} \cw{dsf_merge()}
|
\S{utils-dsf-merge} \cw{dsf_merge()}
|
||||||
|
|
||||||
\c void dsf_merge(int *dsf, int v1, int v2);
|
\c void dsf_merge(DSF *dsf, int v1, int v2);
|
||||||
|
|
||||||
Updates a dsf so that elements \c{v1} and \c{v2} will now be
|
Updates a dsf so that elements \c{v1} and \c{v2} will now be
|
||||||
considered to be in the same equivalence class. If they were already
|
considered to be in the same equivalence class. If they were already
|
||||||
in the same class, this function will safely do nothing.
|
in the same class, this function will safely do nothing.
|
||||||
|
|
||||||
|
This function may not be called on a flip dsf. Use \cw{dsf_merge_flip}
|
||||||
|
instead.
|
||||||
|
|
||||||
\S{utils-dsf-canonify} \cw{dsf_canonify()}
|
\S{utils-dsf-canonify} \cw{dsf_canonify()}
|
||||||
|
|
||||||
\c int dsf_canonify(int *dsf, int val);
|
\c int dsf_canonify(DSF *dsf, int val);
|
||||||
|
|
||||||
Returns the \q{canonical} element of the equivalence class in the dsf
|
Returns the \q{canonical} element of the equivalence class in the dsf
|
||||||
containing \c{val}. This will be some element of the same equivalence
|
containing \c{val}. This will be some element of the same equivalence
|
||||||
@ -4550,12 +4577,9 @@ Canonical elements don't necessarily stay the same if the dsf is
|
|||||||
mutated via \c{dsf_merge}. But between two calls to \c{dsf_merge},
|
mutated via \c{dsf_merge}. But between two calls to \c{dsf_merge},
|
||||||
they stay the same.
|
they stay the same.
|
||||||
|
|
||||||
In this implementation, the canonical element is always the element
|
|
||||||
with smallest index in the equivalence class.
|
|
||||||
|
|
||||||
\S{utils-dsf-size} \cw{dsf_size()}
|
\S{utils-dsf-size} \cw{dsf_size()}
|
||||||
|
|
||||||
\c int dsf_size(int *dsf, int val);
|
\c int dsf_size(DSF *dsf, int val);
|
||||||
|
|
||||||
Returns the number of elements currently in the equivalence class
|
Returns the number of elements currently in the equivalence class
|
||||||
containing \c{val}.
|
containing \c{val}.
|
||||||
@ -4563,60 +4587,72 @@ containing \c{val}.
|
|||||||
\c{val} itself counts, so in a newly created dsf, the return value
|
\c{val} itself counts, so in a newly created dsf, the return value
|
||||||
will be 1.
|
will be 1.
|
||||||
|
|
||||||
\S{utils-edsf-merge} \cw{edsf_merge()}
|
\S{utils-dsf-merge-flip} \cw{dsf_merge_flip()}
|
||||||
|
|
||||||
\c void edsf_merge(int *dsf, int v1, int v2, bool inverse);
|
\c void edsf_merge(DSF *dsf, int v1, int v2, bool flip);
|
||||||
|
|
||||||
Updates an edsf so that elements \c{v1} and \c{v2} are in the same
|
Updates a flip dsf so that elements \c{v1} and \c{v2} are in the same
|
||||||
equivalence class. If \c{inverse} is \cw{false}, they will be regarded
|
equivalence class. If \c{flip} is \cw{false}, they will be regarded as
|
||||||
as also being in the same subclass of that class; if \c{inverse} is
|
in the same state as each other; if \c{flip} is \cw{true} then they
|
||||||
\cw{true} then they will be regarded as being in opposite subclasses.
|
will be regarded as being in opposite states.
|
||||||
|
|
||||||
If \c{v1} and \c{v2} were already in the same equivalence class, then
|
If \c{v1} and \c{v2} were already in the same equivalence class, then
|
||||||
the new value of \c{inverse} will be checked against what the edsf
|
the new value of \c{flip} will be checked against what the edsf
|
||||||
previously believed, and an assertion failure will occur if you
|
previously believed, and an assertion failure will occur if you
|
||||||
contradict that.
|
contradict that.
|
||||||
|
|
||||||
For example, if you start from a blank edsf and do this:
|
For example, if you start from a blank flip dsf and do this:
|
||||||
|
|
||||||
\c edsf_merge(dsf, 0, 1, false);
|
\c dsf_merge_flip(dsf, 0, 1, false);
|
||||||
\c edsf_merge(dsf, 1, 2, true);
|
\c dsf_merge_flip(dsf, 1, 2, true);
|
||||||
|
|
||||||
then it will create a dsf in which elements 0,1,2 are all in the same
|
then it will create a dsf in which elements 0,1,2 are all in the same
|
||||||
class, with one subclasses containing 0,1 and the other containing 2.
|
class, with 0,1 in the same state as each other and 2 in the opposite
|
||||||
And then this call will do nothing, because it agrees with what the
|
state from both. And then this call will do nothing, because it agrees
|
||||||
edsf already knew:
|
with what the dsf already knew:
|
||||||
|
|
||||||
\c edsf_merge(dsf, 0, 2, true);
|
\c dsf_merge_flip(dsf, 0, 2, true);
|
||||||
|
|
||||||
But this call will fail an assertion:
|
But this call will fail an assertion:
|
||||||
|
|
||||||
\c edsf_merge(dsf, 0, 2, false);
|
\c dsf_merge_flip(dsf, 0, 2, false);
|
||||||
|
|
||||||
\S{utils-edsf-canonify} \cw{edsf_canonify()}
|
\S{utils-dsf-canonify-flip} \cw{dsf_canonify_flip()}
|
||||||
|
|
||||||
\c int edsf_canonify(int *dsf, int val, bool *inverse);
|
\c int dsf_canonify_flip(DSF *dsf, int val, bool *inverse);
|
||||||
|
|
||||||
Like \c{dsf_canonify()}, this returns the canonical element of the
|
Like \c{dsf_canonify()}, this returns the canonical element of the
|
||||||
equivalence class of an edsf containing \c{val}. It also fills in
|
equivalence class of a dsf containing \c{val}.
|
||||||
\c{*inverse} with a flag indicating whether \c{val} and the canonical
|
|
||||||
element are in opposite subclasses: \cw{true} if they are in opposite
|
However, it may only be called on a flip dsf, and it also fills in
|
||||||
subclasses, or \cw{false} if they're in the same subclass.
|
\c{*flip} with a flag indicating whether \c{val} and the canonical
|
||||||
|
element are in opposite states: \cw{true} if they are in opposite
|
||||||
|
states, or \cw{false} if they're in the same state.
|
||||||
|
|
||||||
So if you want to know the relationship between \c{v1} and \c{v2}, you
|
So if you want to know the relationship between \c{v1} and \c{v2}, you
|
||||||
can do this:
|
can do this:
|
||||||
|
|
||||||
\c bool inv1, inv2;
|
\c bool inv1, inv2;
|
||||||
\c int canon1 = edsf_canonify(dsf, v1, &inv1);
|
\c int canon1 = dsf_canonify_flip(dsf, v1, &inv1);
|
||||||
\c int canon2 = edsf_canonify(dsf, v2, &inv2);
|
\c int canon2 = dsf_canonify_flip(dsf, v2, &inv2);
|
||||||
\c if (canon1 != canon2) {
|
\c if (canon1 != canon2) {
|
||||||
\c // v1 and v2 have no known relation
|
\c // v1 and v2 have no known relation
|
||||||
\c } else if (inv1 == inv2) {
|
\c } else if (inv1 == inv2) {
|
||||||
\c // v1 and v2 are in the same subclass of the same class
|
\c // v1 and v2 are known to be in the same state as each other
|
||||||
\c } else {
|
\c } else {
|
||||||
\c // v1 and v2 are in opposite subclasses of the same class
|
\c // v1 and v2 are known to be in opposite states
|
||||||
\c }
|
\c }
|
||||||
|
|
||||||
|
\S{utils-dsf-minimal} \cw{dsf_minimal()}
|
||||||
|
|
||||||
|
\c int dsf_minimal(DSF *dsf, int val);
|
||||||
|
|
||||||
|
Returns the smallest element of the equivalence class in the dsf
|
||||||
|
containing \c{val}.
|
||||||
|
|
||||||
|
For this function to work, the dsf must have been created using
|
||||||
|
\cw{dsf_new_min()}.
|
||||||
|
|
||||||
\H{utils-tdq} To-do queues
|
\H{utils-tdq} To-do queues
|
||||||
|
|
||||||
This section describes a set of functions implementing a \q{to-do
|
This section describes a set of functions implementing a \q{to-do
|
||||||
|
Reference in New Issue
Block a user