James Dow Allen said:
[A] Knuth article ...
followed the evolution from a clear to an efficient solution step
by step.
It's probably obvious that my routine is faster than a
"properly written" alternative. My claim is that it may also
be *clearer* once one escapes the mental block of disliking
the peculiar structure. (The alternative will be clumsy.)
Admittedly I should add detailed comments and rewrite some
of the long expressions to make this point. But the "cute"
programming examples I show at my website are a low priority
for me, and I've not received much encouragement here....
Alright, I'll offer some encouragement. Consider an approach along
the following lines.
void
find_optimal_play(){
... a few local variables ...
... initialize ...
FOREVER {
FOREVER {
play one more card from alternatives
set alternatives for next play
if( at end of trick ){
advance state to next trick
if( one side "won" ) break;
}
}
FOREVER {
if( at start of trick ){
if( at first trick ) return;
regress state to previous trick
}
regress state to previous play
undo effects of card played
if( this side should try other plays ) break;
}
}
}
I coded up something along these lines. The control flow is just what
is shown here: three infinite loops, two break's, one return. The
state of the computation was in a data structure much like the one you
used - a stack of "tricks" with information about alternatives and
cards played. Only a few local variables, and I made essentially no
effort to micro-optimize; for example, the suit led is recalculated
each time through the "advance the state" loop:
suit_led = SUIT( S->card_played[ S->on_lead ] );
Except for the different method of doing control flow, the two
programs use basically the same algorithm. The structured code ran
about 25% faster than your code with goto's.
So I guess I'm encouraging you to reconsider whether this problem is a
good example to illustrate when goto's are clearer or faster. Neither
seems to be true in this particular case.