## Programming Example inspired by Dell Logic Puzzles magazine

The source code should be self-explanatory. I found it fun to write because it is tricky to build macros that map a puzzle to appropriate code. (Note that I seemed to need the ``comma'' operator.)

This is just a miniature version of my logic puzzle software. I now produce such puzzles as a vocation, and don't feel like showing all my tools here (though I might share in response to a serious inquiry).

The source contains the general solver, and details of a specific puzzle (though not one good enough to sell to a magazine). Normally the latter would be in a separate included file; indeed much of the macro setup is to facilitate that. This is very similar to code submitted a decade ago to the Rec.Puzzles Archive, though this version fixes a bug seen only with unusually difficult problems.

```

#include

#define EITHER		if (S = S, ! setjmp((S++)->jb)) {
#define OR		} else EITHER
#define REJECT		longjmp((--S)->jb, 1)
#define END_EITHER	} else REJECT;
#define EASY_END	}

/* values in tmat: */
#define T_UNK		0
#define T_YES		1
#define T_NO		2

#define Val(t1,t2)	(S->tmat[t1][t2])
#define CLASS(x)		\
(((x) / NUM_ITEM) * NUM_ITEM)
#define EVERY_TOKEN(x)		\
(x = 0; x < TOT_TOKEN; x++)
#define EVERY_ITEM(x, class)	\
(x = CLASS(class); x < CLASS(class) + NUM_ITEM; x++)

#define	No2(b, cl) {			\
no(b, cl+0); no(b, cl+1); }

#define	No3(b, cl) {			\
No2(b, cl); no(b, cl+2); }

#define	No4(b, cl) {			\
No3(b, cl); no(b, cl+3); }

#define	No5(b, cl) {			\
No4(b, cl); no(b, cl+4); }

#define	lessthan3(a, b, cl) if (a != -1) {	\
EITHER yes(a, cl+0); no(b, cl);		\
OR yes(a, cl+1); No2(b, cl);		\
END_EITHER }

#define	lessthan4(a, b, cl) {			\
EITHER lessthan3(a, b, cl);		\
OR yes(a, cl+2); No3(b, cl);		\
END_EITHER }

#define	lessthan5(a, b, cl) {			\
EITHER lessthan4(a, b, cl);		\
OR yes(a, cl+3); No4(b, cl);		\
END_EITHER }

#define	lessthan6(a, b, cl) {			\
EITHER lessthan5(a, b, cl);		\
OR yes(a, cl+4); No5(b, cl);		\
END_EITHER }

#define	MAXTTOT	30

struct state {
char	tmat[MAXTTOT][MAXTTOT];
long	flug;
jmp_buf jb;
} States, *S = States;

termin()
{
printf("All solutions found\n");
exit(0);
}

#define	PROB_BEGIN			\
main() { register token;	\
int	xx_1;			\
int	aa1, aa2, aa3,		\
aa4, aa5, aa6;	\
for EVERY_TOKEN(token) yes(token, token); EITHER

#define	PROB_END			\
solveit(); OR termin(); END_EITHER }

/* Here is the problem-specific data */

#define NUM_ITEM	6
#define NUM_CLASS	4
#define TOT_TOKEN	(NUM_ITEM * NUM_CLASS)

#define CO_1	0
#define CO_5	1
#define CO_10	2
#define CO_25	3
#define CO_50	4
#define CO_100	5

#define ANNIE	(NUM_ITEM + 0)
#define BETTY	(NUM_ITEM + 1)
#define CHERYL	(NUM_ITEM + 2)
#define DELLA	(NUM_ITEM + 3)
#define ELAINE	(NUM_ITEM + 4)
#define FANNY	(NUM_ITEM + 5)

#define REYNOLD	(NUM_ITEM*2 + 0)
#define TUKEY	(NUM_ITEM*2 + 1)
#define VITTEL	(NUM_ITEM*2 + 2)
#define MORRIS	(NUM_ITEM*2 + 3)
#define UPDIKE	(NUM_ITEM*2 + 4)
#define STOUT	(NUM_ITEM*2 + 5)

#define MONDAY	(NUM_ITEM*3 + 0)
#define TUESDA	(NUM_ITEM*3 + 1)
#define WEDNES	(NUM_ITEM*3 + 2)
#define THURSD	(NUM_ITEM*3 + 3)
#define FRIDAY	(NUM_ITEM*3 + 4)
#define SATURD	(NUM_ITEM*3 + 5)

char *Names[] = {
"CO_1", "CO_5", "CO_10",
"CO_25", "CO_50", "CO_100",

"ANNIE", "BETTY", "CHERYL",
"DELLA", "ELAINE", "FANNY",

"REYNOLD", "TUKEY", "VITTEL",
"WALKER", "UPDIKE", "STOUT",

"MONDAY", "TUESDA", "WEDNES",
"THURSD", "FRIDAY", "SATURD",
};

PROB_BEGIN

/* Clue 1: Annie's coin was twice the value of Tukey's */
EITHER
yes(ANNIE, CO_10);
yes(TUKEY, CO_5);
OR
yes(ANNIE, CO_50);
yes(TUKEY, CO_25);
OR
yes(ANNIE, CO_100);
yes(TUKEY, CO_50);
END_EITHER

/* Clue 2: Wednes coin was five times the value of FANNY's coin */
EITHER
yes(WEDNES, CO_5);
yes(FANNY, CO_1);
OR
yes(WEDNES, CO_25);
yes(FANNY, CO_5);
OR
yes(WEDNES, CO_50);
yes(FANNY, CO_10);
END_EITHER

/* Clue 3: Updike threw before Elaine; Dime was thrown before Vittel' throw */
lessthan6(UPDIKE, ELAINE, MONDAY);
lessthan6(CO_10, VITTEL, MONDAY);

/* Clue 4: BETTY's coin is less than REYNOLD's */
lessthan6(BETTY, REYNOLD, CO_1);

/* Clue 5: Saturd coin was five times the value of STOUT's coin */
EITHER
yes(SATURD, CO_5);
yes(STOUT, CO_1);
OR
yes(SATURD, CO_25);
yes(STOUT, CO_5);
OR
yes(SATURD, CO_50);
yes(STOUT, CO_10);
END_EITHER

/* Clue 6: The nickel came some day after Elaine */
lessthan6(ELAINE, CO_5, MONDAY);

/* Clue 7: 50-cent piece came some day after STOUT */
lessthan6(STOUT, CO_50, MONDAY);

/* Clue 8: Tuesday's coin was five times Cheryl's */
EITHER
yes(TUESDA, CO_25);
yes(CHERYL, CO_5);
OR
yes(TUESDA, CO_50);
yes(CHERYL, CO_10);
OR
yes(TUESDA, CO_5);
yes(CHERYL, CO_1);
END_EITHER

/* Clue 9: Della went earlier in the week than the penny */
lessthan6(DELLA, CO_1, MONDAY);

PROB_END
/* End of problem-specific data */

no(a1, a2)
{
int	non1, non2, token;

if (a1 == -1 || a2 == -1)
return;
if (a1 == a2 || Val(a1, a2) == T_YES)
REJECT;
else if (Val(a1, a2) == T_UNK) {
Val(a1, a2) = T_NO;
no(a2, a1);
non1 = non2 = -1;

for EVERY_ITEM(token, a1)
if (Val(token, a2) != T_NO)
if (non1 == -1)
non1 = token;
else
break;
if (non1 == -1)
REJECT;
else if (token == CLASS(a1) + NUM_ITEM)
yes(non1, a2);

for EVERY_TOKEN(token)
if (Val(token, a1) == T_YES)
no(a2, token);
}
}

yes(a1, a2)
{
int	token;

if (a1 == -2 || a2 == -2)
return;
if (a1 == -1 || a2 == -1)
REJECT;
if (Val(a1, a2) == T_NO)
REJECT;
else if (Val(a1, a2) == T_UNK) {
Val(a1, a2) = T_YES;
yes(a2, a1);
for EVERY_ITEM(token, a1)
if (token != a1)
no(token, a2);
for EVERY_TOKEN(token)
if (Val(token, a1) == T_YES)
yes(a2, token);
else if (Val(token, a1) == T_NO)
no(a2, token);
}
}

solveit()
{
int	token, tok2;

for EVERY_TOKEN(token)
for (tok2 = token; tok2 < TOT_TOKEN; tok2++)
if (Val(token, tok2) == T_UNK) {
EITHER
yes(token, tok2);
OR
no(token, tok2);
END_EITHER;
solveit();
REJECT;
}
printf("Solution:\n");
for EVERY_ITEM(token, 0) {
printf("\t%s", Names[token]);
for (tok2 = NUM_ITEM; tok2 < TOT_TOKEN; tok2++)
if (Val(token, tok2) == T_YES)
printf("\t%s", Names[tok2]);
printf("\n");
}
REJECT;
}
```

Please send me some e-mail.
Go back to my home page.