In Plansim, the way to change the simulator state is through action classes. For the Hanoi domain, we will define a single action, move_disk. This action receives as parameters the disk to be moved, the origin tower and the destination tower.
We will call this class hanoi::move_disk_action. It is derived from plansim::action. We will take as basis the action_template.hpp and action_template.cpp files under the examples/templates directory. These files will be used to create the move_disk_action.hpp and move_disk_action.cpp, respectively. All occurrences of $domain$ in these files are replaced by 'hanoi', and all occurrences of $object$ in these files are replaced by the class name, in our case 'move_disk_action'. For the Hanoi domain we have this single action, for an example of domain defining more than one action see the blocksworld domain under the examples/blocksworld directory.
The move_disk_action constructor looks like:
move_disk_action:: move_disk_action( unsigned int disk_number, unsigned int from_tower, unsigned int to_tower ) : action( 1. ), disk_number_( disk_number ), from_tower_( from_tower ), to_tower_( to_tower ) { }
Note that is is assumed that the action's cost is , this is the argument passed to the action constructor.
The move_disk_action changes, though the execute method implementation, the simulator state. The final code looks like:
void move_disk_action::execute( plansim::simulator& simul ) const { // Simulator must be downcasted from plansim to hanoi simulator simulator* s = dynamic_cast<simulator *>( &simul ); // Modify simulator state at will s->towers_[ from_tower_ ].pop_back(); s->towers_[ to_tower_ ].push_back( disk_number_ ); }
We chose to make hanoi::move_disk_action a hanoi::simulator friend. This is not required, but significantly reduces the necessary coding amount.
Every Plansim action must also define how it is written in a stream. This is used by the framework to show the resulting plan, which is in fact a sequence of actions. This is implemented by the print method. For hanoi::move_disk_action we have:
std::ostream& move_disk_action::print( std::ostream& os ) const { // Action to stream os << "Move disk " << disk_number_ << " from tower " << from_tower_ << " to tower " << to_tower_; return os; }