Recursion is just like what you showed. If routine A calls A, or if A calls B and B calls A, that is recursion.
Backtrack is not an algorithm, it is a control structure. When using backtrack, a program appears to be able to run backward. This is useful when writing a program to play a game like chess, where you want to look ahead some number of moves. When the program wants to make a move, it picks a move, then switches to its mirror-image opponent program, which picks a move, and so on. If the initial program gets to a "good place" it wants to say "Yay" and carry out the first move it made. If either program gets to a "bad place" it wants to back out and try another move.
You could just think of this as searching a tree, but if the move choices are complicated it may be more intuitive to think of it as a program "backing up" to the last place it chose a move, choosing a different move, and running forward again.
OK, so if that idea has appeal, how do you do it?
First, you need a kind of statement representing a choice
, where a move is chosen, that you can "back up" to and revise your choice.
Second, whenever you have a sequence of statements like A;B
, you make A
a function, and you pass to it a function capable of executing B
. Something like A(lambda()B(...))
. So when A
is finished executing, before returning it calls its argument that executes B
.
If A
wants to "fail" and start "running backward" it simply returns without calling the function that calls B
.
I know this is hard to follow. I've done it via macros in LISP, and it works well. To do it in a normal compiler language like C++ is incredibly hairy.
I have done something like it in C/C++ in a way that preserves the "prettiness" but doesn't actually run backwards.
The idea is you're doing this to perform some kind of depth-first tree search.
But you could do it instead as a series of "stabs" down from the root of the tree, following a different path each time you "stab".
This might be objected to on performance grounds, but it doesn't actually cost that much more, since the bulk of the work happens in the leaves of the tree. If the tree is 3 layers deep and has a branching factor of 5 at each node, that means it has 5 + 25 + 125 or 155 nodes. But in a series of "stabs" from the root, it visits 125 * 3 = 375 nodes, a performance penalty of less than 3x, which can be quite tolerable unless performance is really a problem. (Remember that real backtrack can involve quite a bit of machinery, making lambdas and so on.)
Here's the basic code I did it with:
#define NLEVEL 20
int ia[NLEVEL];
int na[NLEVEL];
int iLevel = 0;
int choose(int n){
if (ilevel >= ns){ na[ns]=n; ia[ns]=0; ns++; }
return ia[ilevel++];
}
void step(){
while (ns > 0){
if (++ia[ns-1] >= na[ns-1]) ns--;
else break;
}
}
bool search(int iLevel){
iLevel++;
switch(choose(2)){
break; case 0:;
// see if 0 is a win. if not, fail by returning false
break; case 1:
// choose move 1 and recur
return search(iLevel);
}
return true;
}
// this is the "top level" routine
void running(){
ns = 0;
// repeat for stabs into choice tree until success
do {
bool bSuccess = search(0);
if (bSuccess){
// Yay!
break;
}
step(); // this advances the stack of choices
} while(ns > 0); // stop when success or there are no more choices
}
I've used this code to build a home-grown theorem prover in place of the search
routine.
ar
isn't even defined in the code you supply. – Militant