The simplest implementation of a focus is perhaps a pass focus. The job of a pass focus is to look at a LocalFocus after a pass. It does this by doing a pass as it's own move. An adding the LocalFocus as it's own child. It overrides the search tree management to make sure it reports the correct values to it's parent (would probably work with out this but who cares).
class PassFocus:public virtual Focus
{
public:
PassFocus(LocalFocus *focus):_LocalFocus(focus) {;}
void doMove();
void unMove();
VisitStat doVisit(Knot *);
const char *description()const { return "PassFocus"; }
// We want to do a search takeover
BOOL searchTakeOver() const { return TRUE;}
Knot * selectChild(Knot *knotNow);
BOOL updateParent(Knot *parent);
void setChildVirtuallyGone(Knot *child);
protected:
LocalFocus *_localFocus;
};
This as you will notice implements a search take over over which overrides the default handling of child selection and updating during the search procedure. This allows you to implement your own methods for traversing the search tree if you should so desire. The main reason in this case however is because they are so simple for the pass case.
The doVisit is only called once when the search engine first comes to a Knot. A focus doe s not store the knot it is associated with (in fact a focii could be associated with more then one knot !!!!) The search tree kindly passes the knot as an argument to routines that might require it. The doVisit typically does an evaluation based on the board state. If it's objective is still undecided it will add children to the search tree and return. In the case of a pass focus it never does an evaluation (I think this is OK?). It simply adds a new child knot (with the correct viewpoint) with the given LocalFocus. Note how beautifully the abstract OO stuff works, the PassFocus does not need to know what sort of LocalFocus it is dealing with ! IT CAN BE USED FOR ANY LOCALFOCUS. PassFocus is required to ask the LocalFocus if the current player is trying to prove or disprove it's objective. It then adds the correct type of Knot. This is the only interaction that is require with the search tree, the planting of Knots. (Gosh this tree terminology is a bit weird "planting a knot that is really a new leaf which becomes a seed for it's children" !!!!)
VisitStat
PassFocus::doVisit(Knot *knot)
{
doMove();
switch(_localFocus->viewPoint())
{
/* The arguments are the focus proofNumber refuteNumber and parent */
case PROVER:
new FocusProofKnot(_localFocus,1,1,knot);
break;
case REFUTER:
new FocusRefuteKnot(_localFocus,1,1,knot);
break;
}
return NORMALVISIT;
}
void
PassFocus::doMove()
{
LowBoard::the()->move(Point::passPoint());
}
void
PassFocus::unMove()
{
LowBoard::the()->takeBack();
}
The Focus::updateParent() function must set it's own proof numbers.
In fact we look forward to the day with have more information and use
the Knots own copy data functions. It is also obliged to tell the
search engine if it's state has changed. If a update parent does not
change the parents state we look down from that node (we did it last
time and it's state is still the same, makes sense ? In this case
however it always changes (trust me it does)
BOOL
PassFocus::updateParent(Knot *parent)
{
// just in case Mr Cockup is lurking about (I am only child check)
assert(parent->child() == parent->child()->nextSibling());
// Could not be simpler my data is the same as my child's data.
parent->copyDataFrom(parent->child());
return TRUE;
}
// If we are diving down the search tree we only have one choice
Knot *
PassFocus::selectChild(Knot *parent)
{
Knot *child1=parent->child();
assert(child1 != NULL );
return child1;
}
// Sometimes we want to pretend we do not exist (never in this case)
void
PassFocus::setChildVirtuallyGone(Knot *)
{
assert(0);
}