mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-22 16:32:13 -07:00
New -A mode permitting even madder operators, and also -m to try to
print all possible paths to a value. The latter has a lot of de-duplication left to be done, due to multiple evaluation orders. [originally from svn r8061]
This commit is contained in:
@ -37,8 +37,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "puzzles.h"
|
#include "puzzles.h"
|
||||||
#include "tree234.h"
|
#include "tree234.h"
|
||||||
@ -87,13 +89,19 @@
|
|||||||
|
|
||||||
struct sets;
|
struct sets;
|
||||||
|
|
||||||
|
struct ancestor {
|
||||||
|
struct set *prev; /* index of ancestor set in set list */
|
||||||
|
unsigned char pa, pb, po, pr; /* operation that got here from prev */
|
||||||
|
};
|
||||||
|
|
||||||
struct set {
|
struct set {
|
||||||
int *numbers; /* rationals stored as n,d pairs */
|
int *numbers; /* rationals stored as n,d pairs */
|
||||||
short nnumbers; /* # of rationals, so half # of ints */
|
short nnumbers; /* # of rationals, so half # of ints */
|
||||||
short flags; /* SETFLAG_CONCAT only, at present */
|
short flags; /* SETFLAG_CONCAT only, at present */
|
||||||
struct set *prev; /* index of ancestor set in set list */
|
|
||||||
unsigned char pa, pb, po, pr; /* operation that got here from prev */
|
|
||||||
int npaths; /* number of ways to reach this set */
|
int npaths; /* number of ways to reach this set */
|
||||||
|
struct ancestor a; /* primary ancestor */
|
||||||
|
struct ancestor *as; /* further ancestors, if we care */
|
||||||
|
int nas, assize;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct output {
|
struct output {
|
||||||
@ -121,6 +129,8 @@ struct sets {
|
|||||||
|
|
||||||
#define OPFLAG_NEEDS_CONCAT 1
|
#define OPFLAG_NEEDS_CONCAT 1
|
||||||
#define OPFLAG_KEEPS_CONCAT 2
|
#define OPFLAG_KEEPS_CONCAT 2
|
||||||
|
#define OPFLAG_UNARY 4
|
||||||
|
#define OPFLAG_UNARYPFX 8
|
||||||
|
|
||||||
struct operation {
|
struct operation {
|
||||||
/*
|
/*
|
||||||
@ -195,7 +205,10 @@ struct rules {
|
|||||||
|
|
||||||
#define OUT(output, n, d) do { \
|
#define OUT(output, n, d) do { \
|
||||||
int g = gcd((n),(d)); \
|
int g = gcd((n),(d)); \
|
||||||
|
if (g < 0) g = -g; \
|
||||||
if ((d) < 0) g = -g; \
|
if ((d) < 0) g = -g; \
|
||||||
|
if (g == -1 && (n) < -INT_MAX) return FALSE; \
|
||||||
|
if (g == -1 && (d) < -INT_MAX) return FALSE; \
|
||||||
(output)[0] = (n)/g; \
|
(output)[0] = (n)/g; \
|
||||||
(output)[1] = (d)/g; \
|
(output)[1] = (d)/g; \
|
||||||
assert((output)[1] > 0); \
|
assert((output)[1] > 0); \
|
||||||
@ -299,9 +312,10 @@ static int perform_concat(int *a, int *b, int *output)
|
|||||||
int t1, t2, p10;
|
int t1, t2, p10;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't concatenate anything which isn't an integer.
|
* We can't concatenate anything which isn't a non-negative
|
||||||
|
* integer.
|
||||||
*/
|
*/
|
||||||
if (a[1] != 1 || b[1] != 1)
|
if (a[1] != 1 || b[1] != 1 || a[0] < 0 || b[0] < 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -341,6 +355,78 @@ static int perform_concat(int *a, int *b, int *output)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IPOW(ret, x, y) do { \
|
||||||
|
int ipow_limit = (y); \
|
||||||
|
if ((x) == 1 || (x) == 0) ipow_limit = 1; \
|
||||||
|
else if ((x) == -1) ipow_limit &= 1; \
|
||||||
|
(ret) = 1; \
|
||||||
|
while (ipow_limit-- > 0) { \
|
||||||
|
int tmp; \
|
||||||
|
MUL(tmp, ret, x); \
|
||||||
|
ret = tmp; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static int perform_exp(int *a, int *b, int *output)
|
||||||
|
{
|
||||||
|
int an, ad, xn, xd, limit, t, i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exponentiation is permitted if the result is rational. This
|
||||||
|
* means that:
|
||||||
|
*
|
||||||
|
* - first we see whether we can take the (denominator-of-b)th
|
||||||
|
* root of a and get a rational; if not, we give up.
|
||||||
|
*
|
||||||
|
* - then we do take that root of a
|
||||||
|
*
|
||||||
|
* - then we multiply by itself (numerator-of-b) times.
|
||||||
|
*/
|
||||||
|
if (b[1] > 1) {
|
||||||
|
an = 0.5 + pow(a[0], 1.0/b[1]);
|
||||||
|
ad = 0.5 + pow(a[1], 1.0/b[1]);
|
||||||
|
IPOW(xn, an, b[1]);
|
||||||
|
IPOW(xd, ad, b[1]);
|
||||||
|
if (xn != a[0] || xd != a[1])
|
||||||
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
an = a[0];
|
||||||
|
ad = a[1];
|
||||||
|
}
|
||||||
|
if (b[0] >= 0) {
|
||||||
|
IPOW(xn, an, b[0]);
|
||||||
|
IPOW(xd, ad, b[0]);
|
||||||
|
} else {
|
||||||
|
IPOW(xd, an, -b[0]);
|
||||||
|
IPOW(xn, ad, -b[0]);
|
||||||
|
}
|
||||||
|
if (xd == 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
OUT(output, xn, xd);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int perform_factorial(int *a, int *b, int *output)
|
||||||
|
{
|
||||||
|
int ret, t, i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Factorials of non-negative integers are permitted.
|
||||||
|
*/
|
||||||
|
if (a[1] != 1 || a[0] < 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
for (i = 1; i <= a[0]; i++) {
|
||||||
|
MUL(t, ret, i);
|
||||||
|
ret = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
OUT(output, ret, 1);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
const static struct operation op_add = {
|
const static struct operation op_add = {
|
||||||
TRUE, "+", 0, 10, 0, TRUE, perform_add
|
TRUE, "+", 0, 10, 0, TRUE, perform_add
|
||||||
};
|
};
|
||||||
@ -360,6 +446,12 @@ const static struct operation op_concat = {
|
|||||||
FALSE, "", OPFLAG_NEEDS_CONCAT | OPFLAG_KEEPS_CONCAT,
|
FALSE, "", OPFLAG_NEEDS_CONCAT | OPFLAG_KEEPS_CONCAT,
|
||||||
1000, 0, FALSE, perform_concat
|
1000, 0, FALSE, perform_concat
|
||||||
};
|
};
|
||||||
|
const static struct operation op_exp = {
|
||||||
|
TRUE, "^", 0, 30, 1, FALSE, perform_exp
|
||||||
|
};
|
||||||
|
const static struct operation op_factorial = {
|
||||||
|
TRUE, "!", OPFLAG_UNARY, 40, 0, FALSE, perform_factorial
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In Countdown, divisions resulting in fractions are disallowed.
|
* In Countdown, divisions resulting in fractions are disallowed.
|
||||||
@ -395,6 +487,17 @@ const static struct rules rules_four4s = {
|
|||||||
ops_four4s, TRUE
|
ops_four4s, TRUE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The most permissive ruleset I can think of. Permits
|
||||||
|
* exponentiation, and also silly unary operators like factorials.
|
||||||
|
*/
|
||||||
|
const static struct operation *const ops_anythinggoes[] = {
|
||||||
|
&op_add, &op_mul, &op_sub, &op_div, &op_concat, &op_exp, &op_factorial, NULL
|
||||||
|
};
|
||||||
|
const static struct rules rules_anythinggoes = {
|
||||||
|
ops_anythinggoes, TRUE
|
||||||
|
};
|
||||||
|
|
||||||
#define ratcmp(a,op,b) ( (long long)(a)[0] * (b)[1] op \
|
#define ratcmp(a,op,b) ( (long long)(a)[0] * (b)[1] op \
|
||||||
(long long)(b)[0] * (a)[1] )
|
(long long)(b)[0] * (a)[1] )
|
||||||
|
|
||||||
@ -480,7 +583,8 @@ static int outputfindcmp(void *av, void *bv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addset(struct sets *s, struct set *set, struct set *prev)
|
static void addset(struct sets *s, struct set *set, int multiple,
|
||||||
|
struct set *prev, int pa, int po, int pb, int pr)
|
||||||
{
|
{
|
||||||
struct set *s2;
|
struct set *s2;
|
||||||
int npaths = (prev ? prev->npaths : 1);
|
int npaths = (prev ? prev->npaths : 1);
|
||||||
@ -491,15 +595,36 @@ static void addset(struct sets *s, struct set *set, struct set *prev)
|
|||||||
/*
|
/*
|
||||||
* New set added to the tree.
|
* New set added to the tree.
|
||||||
*/
|
*/
|
||||||
set->prev = prev;
|
set->a.prev = prev;
|
||||||
|
set->a.pa = pa;
|
||||||
|
set->a.po = po;
|
||||||
|
set->a.pb = pb;
|
||||||
|
set->a.pr = pr;
|
||||||
set->npaths = npaths;
|
set->npaths = npaths;
|
||||||
s->nsets++;
|
s->nsets++;
|
||||||
s->nnumbers += 2 * set->nnumbers;
|
s->nnumbers += 2 * set->nnumbers;
|
||||||
|
set->as = NULL;
|
||||||
|
set->nas = set->assize = 0;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Rediscovered an existing set. Update its npaths only.
|
* Rediscovered an existing set. Update its npaths.
|
||||||
*/
|
*/
|
||||||
s2->npaths += npaths;
|
s2->npaths += npaths;
|
||||||
|
/*
|
||||||
|
* And optionally enter it as an additional ancestor.
|
||||||
|
*/
|
||||||
|
if (multiple) {
|
||||||
|
if (s2->nas >= s2->assize) {
|
||||||
|
s2->assize = s2->nas * 3 / 2 + 4;
|
||||||
|
s2->as = sresize(s2->as, s2->assize, struct ancestor);
|
||||||
|
}
|
||||||
|
s2->as[s2->nas].prev = prev;
|
||||||
|
s2->as[s2->nas].pa = pa;
|
||||||
|
s2->as[s2->nas].po = po;
|
||||||
|
s2->as[s2->nas].pb = pb;
|
||||||
|
s2->as[s2->nas].pr = pr;
|
||||||
|
s2->nas++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,7 +689,8 @@ static int addoutput(struct sets *s, struct set *ss, int index, int *n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct sets *do_search(int ninputs, int *inputs,
|
static struct sets *do_search(int ninputs, int *inputs,
|
||||||
const struct rules *rules, int *target)
|
const struct rules *rules, int *target,
|
||||||
|
int multiple)
|
||||||
{
|
{
|
||||||
struct sets *s;
|
struct sets *s;
|
||||||
struct set *sn;
|
struct set *sn;
|
||||||
@ -592,7 +718,7 @@ static struct sets *do_search(int ninputs, int *inputs,
|
|||||||
newnumber[1] = 1;
|
newnumber[1] = 1;
|
||||||
addtoset(sn, newnumber);
|
addtoset(sn, newnumber);
|
||||||
}
|
}
|
||||||
addset(s, sn, NULL);
|
addset(s, sn, multiple, NULL, 0, 0, 0, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now perform the breadth-first search: keep looping over sets
|
* Now perform the breadth-first search: keep looping over sets
|
||||||
@ -627,13 +753,17 @@ static struct sets *do_search(int ninputs, int *inputs,
|
|||||||
!(ss->flags & SETFLAG_CONCAT))
|
!(ss->flags & SETFLAG_CONCAT))
|
||||||
continue; /* can't use this operation here */
|
continue; /* can't use this operation here */
|
||||||
for (i = 0; i < ss->nnumbers; i++) {
|
for (i = 0; i < ss->nnumbers; i++) {
|
||||||
for (j = 0; j < ss->nnumbers; j++) {
|
int jlimit = (ops[k]->flags & OPFLAG_UNARY ? 1 : ss->nnumbers);
|
||||||
|
for (j = 0; j < jlimit; j++) {
|
||||||
int n[2];
|
int n[2];
|
||||||
|
int pa, po, pb, pr;
|
||||||
|
|
||||||
if (i == j)
|
if (!(ops[k]->flags & OPFLAG_UNARY)) {
|
||||||
continue; /* can't combine a number with itself */
|
if (i == j)
|
||||||
if (i > j && ops[k]->commutes)
|
continue; /* can't combine a number with itself */
|
||||||
continue; /* no need to do this both ways round */
|
if (i > j && ops[k]->commutes)
|
||||||
|
continue; /* no need to do this both ways round */
|
||||||
|
}
|
||||||
if (!ops[k]->perform(ss->numbers+2*i, ss->numbers+2*j, n))
|
if (!ops[k]->perform(ss->numbers+2*i, ss->numbers+2*j, n))
|
||||||
continue; /* operation failed */
|
continue; /* operation failed */
|
||||||
|
|
||||||
@ -643,17 +773,21 @@ static struct sets *do_search(int ninputs, int *inputs,
|
|||||||
sn->flags &= ~SETFLAG_CONCAT;
|
sn->flags &= ~SETFLAG_CONCAT;
|
||||||
|
|
||||||
for (m = 0; m < ss->nnumbers; m++) {
|
for (m = 0; m < ss->nnumbers; m++) {
|
||||||
if (m == i || m == j)
|
if (m == i || (!(ops[k]->flags & OPFLAG_UNARY) &&
|
||||||
|
m == j))
|
||||||
continue;
|
continue;
|
||||||
sn->numbers[2*sn->nnumbers] = ss->numbers[2*m];
|
sn->numbers[2*sn->nnumbers] = ss->numbers[2*m];
|
||||||
sn->numbers[2*sn->nnumbers + 1] = ss->numbers[2*m + 1];
|
sn->numbers[2*sn->nnumbers + 1] = ss->numbers[2*m + 1];
|
||||||
sn->nnumbers++;
|
sn->nnumbers++;
|
||||||
}
|
}
|
||||||
sn->pa = i;
|
pa = i;
|
||||||
sn->pb = j;
|
if (ops[k]->flags & OPFLAG_UNARY)
|
||||||
sn->po = k;
|
pb = sn->nnumbers+10;
|
||||||
sn->pr = addtoset(sn, n);
|
else
|
||||||
addset(s, sn, ss);
|
pb = j;
|
||||||
|
po = k;
|
||||||
|
pr = addtoset(sn, n);
|
||||||
|
addset(s, sn, multiple, ss, pa, po, pb, pr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -683,13 +817,15 @@ static void free_sets(struct sets *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct a text formula for producing a given output.
|
* Print a text formula for producing a given output.
|
||||||
*/
|
*/
|
||||||
void mkstring_recurse(char **str, int *len,
|
void print_recurse(struct sets *s, struct set *ss, int pathindex, int index,
|
||||||
struct sets *s, struct set *ss, int index,
|
int priority, int assoc, int child);
|
||||||
int priority, int assoc, int child)
|
void print_recurse_inner(struct sets *s, struct set *ss,
|
||||||
|
struct ancestor *a, int pathindex, int index,
|
||||||
|
int priority, int assoc, int child)
|
||||||
{
|
{
|
||||||
if (ss->prev && index != ss->pr) {
|
if (a->prev && index != a->pr) {
|
||||||
int pi;
|
int pi;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -698,17 +834,17 @@ void mkstring_recurse(char **str, int *len,
|
|||||||
* recurse to there.
|
* recurse to there.
|
||||||
*/
|
*/
|
||||||
pi = index;
|
pi = index;
|
||||||
assert(pi != ss->pr);
|
assert(pi != a->pr);
|
||||||
if (pi > ss->pr)
|
if (pi > a->pr)
|
||||||
pi--;
|
pi--;
|
||||||
if (pi >= min(ss->pa, ss->pb)) {
|
if (pi >= min(a->pa, a->pb)) {
|
||||||
pi++;
|
pi++;
|
||||||
if (pi >= max(ss->pa, ss->pb))
|
if (pi >= max(a->pa, a->pb))
|
||||||
pi++;
|
pi++;
|
||||||
}
|
}
|
||||||
mkstring_recurse(str, len, s, ss->prev, pi, priority, assoc, child);
|
print_recurse(s, a->prev, pathindex, pi, priority, assoc, child);
|
||||||
} else if (ss->prev && index == ss->pr &&
|
} else if (a->prev && index == a->pr &&
|
||||||
s->ops[ss->po]->display) {
|
s->ops[a->po]->display) {
|
||||||
/*
|
/*
|
||||||
* This number was created by a displayed operator in the
|
* This number was created by a displayed operator in the
|
||||||
* transition from this set to its predecessor. Hence we
|
* transition from this set to its predecessor. Hence we
|
||||||
@ -722,66 +858,67 @@ void mkstring_recurse(char **str, int *len,
|
|||||||
/*
|
/*
|
||||||
* Determine whether we need parentheses.
|
* Determine whether we need parentheses.
|
||||||
*/
|
*/
|
||||||
thispri = s->ops[ss->po]->priority;
|
thispri = s->ops[a->po]->priority;
|
||||||
thisassoc = s->ops[ss->po]->assoc;
|
thisassoc = s->ops[a->po]->assoc;
|
||||||
parens = (thispri < priority ||
|
parens = (thispri < priority ||
|
||||||
(thispri == priority && (assoc & child)));
|
(thispri == priority && (assoc & child)));
|
||||||
|
|
||||||
if (parens) {
|
if (parens)
|
||||||
if (str)
|
putchar('(');
|
||||||
*(*str)++ = '(';
|
|
||||||
if (len)
|
if (s->ops[a->po]->flags & OPFLAG_UNARYPFX)
|
||||||
(*len)++;
|
for (op = s->ops[a->po]->text; *op; op++)
|
||||||
}
|
putchar(*op);
|
||||||
mkstring_recurse(str, len, s, ss->prev, ss->pa, thispri, thisassoc, 1);
|
|
||||||
for (op = s->ops[ss->po]->text; *op; op++) {
|
print_recurse(s, a->prev, pathindex, a->pa, thispri, thisassoc, 1);
|
||||||
if (str)
|
|
||||||
*(*str)++ = *op;
|
if (!(s->ops[a->po]->flags & OPFLAG_UNARYPFX))
|
||||||
if (len)
|
for (op = s->ops[a->po]->text; *op; op++)
|
||||||
(*len)++;
|
putchar(*op);
|
||||||
}
|
|
||||||
mkstring_recurse(str, len, s, ss->prev, ss->pb, thispri, thisassoc, 2);
|
if (!(s->ops[a->po]->flags & OPFLAG_UNARY))
|
||||||
if (parens) {
|
print_recurse(s, a->prev, pathindex, a->pb, thispri, thisassoc, 2);
|
||||||
if (str)
|
|
||||||
*(*str)++ = ')';
|
if (parens)
|
||||||
if (len)
|
putchar(')');
|
||||||
(*len)++;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* This number is either an original, or something formed
|
* This number is either an original, or something formed
|
||||||
* by a non-displayed operator (concatenation). Either way,
|
* by a non-displayed operator (concatenation). Either way,
|
||||||
* we display it as is.
|
* we display it as is.
|
||||||
*/
|
*/
|
||||||
char buf[80], *p;
|
printf("%d", ss->numbers[2*index]);
|
||||||
int blen;
|
|
||||||
blen = sprintf(buf, "%d", ss->numbers[2*index]);
|
|
||||||
if (ss->numbers[2*index+1] != 1)
|
if (ss->numbers[2*index+1] != 1)
|
||||||
blen += sprintf(buf+blen, "/%d", ss->numbers[2*index+1]);
|
printf("/%d", ss->numbers[2*index+1]);
|
||||||
assert(blen < lenof(buf));
|
}
|
||||||
for (p = buf; *p; p++) {
|
}
|
||||||
if (str)
|
void print_recurse(struct sets *s, struct set *ss, int pathindex, int index,
|
||||||
*(*str)++ = *p;
|
int priority, int assoc, int child)
|
||||||
if (len)
|
{
|
||||||
(*len)++;
|
if (!ss->a.prev || pathindex < ss->a.prev->npaths) {
|
||||||
|
print_recurse_inner(s, ss, &ss->a, pathindex,
|
||||||
|
index, priority, assoc, child);
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
pathindex -= ss->a.prev->npaths;
|
||||||
|
for (i = 0; i < ss->nas; i++) {
|
||||||
|
if (pathindex < ss->as[i].prev->npaths) {
|
||||||
|
print_recurse_inner(s, ss, &ss->as[i], pathindex,
|
||||||
|
index, priority, assoc, child);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pathindex -= ss->as[i].prev->npaths;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
char *mkstring(struct sets *s, struct output *o)
|
void print(int pathindex, struct sets *s, struct output *o)
|
||||||
{
|
{
|
||||||
int len;
|
print_recurse(s, o->set, pathindex, o->index, 0, 0, 0);
|
||||||
char *str, *p;
|
|
||||||
|
|
||||||
len = 0;
|
|
||||||
mkstring_recurse(NULL, &len, s, o->set, o->index, 0, 0, 0);
|
|
||||||
str = snewn(len+1, char);
|
|
||||||
p = str;
|
|
||||||
mkstring_recurse(&p, NULL, s, o->set, o->index, 0, 0, 0);
|
|
||||||
assert(p - str <= len);
|
|
||||||
*p = '\0';
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gcc -g -O0 -o numgame numgame.c -I.. ../{malloc,tree234,nullfe}.c -lm
|
||||||
|
*/
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int doing_opts = TRUE;
|
int doing_opts = TRUE;
|
||||||
@ -791,6 +928,7 @@ int main(int argc, char **argv)
|
|||||||
int numbers[10], nnumbers = 0;
|
int numbers[10], nnumbers = 0;
|
||||||
int verbose = FALSE;
|
int verbose = FALSE;
|
||||||
int pathcounts = FALSE;
|
int pathcounts = FALSE;
|
||||||
|
int multiple = FALSE;
|
||||||
|
|
||||||
struct output *o;
|
struct output *o;
|
||||||
struct sets *s;
|
struct sets *s;
|
||||||
@ -816,12 +954,18 @@ int main(int argc, char **argv)
|
|||||||
case 'D':
|
case 'D':
|
||||||
rules = &rules_four4s;
|
rules = &rules_four4s;
|
||||||
break;
|
break;
|
||||||
|
case 'A':
|
||||||
|
rules = &rules_anythinggoes;
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = TRUE;
|
verbose = TRUE;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
pathcounts = TRUE;
|
pathcounts = TRUE;
|
||||||
break;
|
break;
|
||||||
|
case 'm':
|
||||||
|
multiple = TRUE;
|
||||||
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
{
|
{
|
||||||
char *v;
|
char *v;
|
||||||
@ -860,7 +1004,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!rules) {
|
if (!rules) {
|
||||||
fprintf(stderr, "%s: no rule set specified; use -C,-B,-D\n", pname);
|
fprintf(stderr, "%s: no rule set specified; use -C,-B,-D,-A\n", pname);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -869,7 +1013,8 @@ int main(int argc, char **argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = do_search(nnumbers, numbers, rules, (got_target ? &target : NULL));
|
s = do_search(nnumbers, numbers, rules, (got_target ? &target : NULL),
|
||||||
|
multiple);
|
||||||
|
|
||||||
if (got_target) {
|
if (got_target) {
|
||||||
o = findrelpos234(s->outputtree, &target, outputfindcmp,
|
o = findrelpos234(s->outputtree, &target, outputfindcmp,
|
||||||
@ -892,20 +1037,31 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = start; i < limit; i++) {
|
for (i = start; i < limit; i++) {
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
o = index234(s->outputtree, i);
|
o = index234(s->outputtree, i);
|
||||||
|
|
||||||
printf("%d", o->number);
|
sprintf(buf, "%d", o->number);
|
||||||
|
|
||||||
if (pathcounts)
|
if (pathcounts)
|
||||||
printf(" [%d]", o->npaths);
|
sprintf(buf + strlen(buf), " [%d]", o->npaths);
|
||||||
|
|
||||||
if (got_target || verbose) {
|
if (got_target || verbose) {
|
||||||
char *p = mkstring(s, o);
|
int j, npaths;
|
||||||
printf(" = %s", p);
|
|
||||||
sfree(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
if (multiple)
|
||||||
|
npaths = o->npaths;
|
||||||
|
else
|
||||||
|
npaths = 1;
|
||||||
|
|
||||||
|
for (j = 0; j < npaths; j++) {
|
||||||
|
printf("%s = ", buf);
|
||||||
|
print(j, s, o);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("%s\n", buf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free_sets(s);
|
free_sets(s);
|
||||||
|
Reference in New Issue
Block a user