builder.hpp

Go to the documentation of this file.
00001 
00028 #ifndef MSMAZES_CORE_FSM_BUILDER_HPP
00029 #define MSMAZES_CORE_FSM_BUILDER_HPP
00030 
00031 // std::map
00032 #include <map>
00033 // std::random_shuffle
00034 #include <algorithm>
00035 // std::pair and std::make_pair
00036 #include <utility>
00037 // boost::function_requires and basic concept check templates
00038 #include <boost/concept_check.hpp>
00039 // boost::tie
00040 #include <boost/utility.hpp>
00041 // boost::is_same
00042 #include <boost/type_traits/is_same.hpp>
00043 // boost::mpl::true_ and boost::mpl::false_
00044 #include <boost/mpl/bool.hpp>
00045 // boost::random_number_generator
00046 #include <boost/random/random_number_generator.hpp>
00047 // boost::queue
00048 #include <boost/pending/queue.hpp>
00049 // boost::property_map, boost::associative_property_map,
00050 // boost::make_iterator_property_map, and boost::get
00051 #include <boost/property_map.hpp>
00052 // boost::graph_traits
00053 #include <boost/graph/graph_traits.hpp>
00054 // boost::vertex_index_t
00055 #include <boost/graph/properties.hpp>
00056 // boost::predecessor_recorder and boost::null_visitor
00057 #include <boost/graph/visitors.hpp>
00058 // boost::breadth_first_visit, boost::bfs_visitor, and boost::make_bfs_visitor
00059 #include <boost/graph/breadth_first_search.hpp>
00060 // boost::make_reverse_graph
00061 #include <boost/graph/reverse_graph.hpp>
00062 // msmazes::MazeStruct
00063 #include <msmazes/core/maze/struct.hpp>
00064 // msmazes::MazeMakerTraits
00065 #include <msmazes/core/maze/traits_maker.hpp>
00066 // msmazes::FSMInputMakerTraits
00067 #include <msmazes/core/fsm/input/traits_maker.hpp>
00068 // msmazes::FSMNoInputMaker
00069 #include <msmazes/core/fsm/input/maker_no.hpp>
00070 
00530 namespace msmazes {
00531 
00533 
00554 struct DefaultArgumentValidationPolicy
00555 {
00559     template <
00560         typename MazeMaker
00561       , typename FSMInputMaker
00562       , typename MazePolicy
00563       , typename ArgumentPack
00564     >
00565     static bool
00566         areValidArguments(
00567             const MazeMaker& maze_maker
00568           , const FSMInputMaker& input_maker
00569           , const MazePolicy& policy
00570           , const ArgumentPack& p
00571         )
00572     {
00573         return true;
00574     }
00575 };
00576 
00578 
00637 template <
00638 #ifndef MSMAZES_DOX
00639     typename PatternType
00640   , typename ArgumentValidationPolicyType = DefaultArgumentValidationPolicy
00641 #endif  /* MSMAZES_DOX */
00642 >
00643 class FSMBuilder
00644 {
00645  public:
00652 #ifdef MSMAZES_DOX
00653     typedef implementation_defined ArgumentValidationPolicy;
00654 #else
00655     typedef ArgumentValidationPolicyType
00656             ArgumentValidationPolicy;
00657 #endif  /* MSMAZES_DOX */
00658 
00664 #ifdef MSMAZES_DOX
00665     typedef implementation_defined Pattern;
00666 #else
00667     typedef PatternType
00668             Pattern;
00669 #endif  /* MSMAZES_DOX */
00670 
00676 #ifdef MSMAZES_DOX
00677     typedef implementation_defined Cell;
00678 #else
00679     typedef typename Pattern::Cell
00680             Cell;
00681 #endif  /* MSMAZES_DOX */
00682 
00689 #ifdef MSMAZES_DOX
00690     typedef implementation_defined Direction;
00691 #else
00692     typedef typename Pattern::Direction
00693             Direction;
00694 #endif  /* MSMAZES_DOX */
00695 
00696  private:
00697     typedef typename Pattern::CellIndex
00698             CellIndex;
00699 
00700  protected:
00705 #ifdef MSMAZES_DOX
00706     typedef implementation_defined MazeStructType;
00707 #else
00708     typedef MazeStruct<CellIndex>
00709             MazeStructType;
00710 #endif  /* MSMAZES_DOX */
00711 
00712  public:
00718 #ifdef MSMAZES_DOX
00719     typedef unspecified MazeGraph;
00720 #else
00721     typedef typename MazeStructType::Graph
00722             MazeGraph;
00723 #endif  /* MSMAZES_DOX */
00724 
00730 #ifdef MSMAZES_DOX
00731     typedef unspecified InputIndex;
00732 #else
00733     typedef typename MazeStructType::EdgeIndex
00734             InputIndex;
00735 #endif  /* MSMAZES_DOX */
00736 
00737  private:
00738     typedef boost::graph_traits<MazeGraph>
00739             MazeGraphTraits;
00740     typedef typename MazeStructType::Vertex
00741             MazeVertex;
00742     typedef typename MazeGraphTraits::vertex_iterator
00743             MazeVertexIterator;
00744     typedef typename MazeGraphTraits::out_edge_iterator
00745             MazeOutEdgeIterator;
00746     typedef std::map<MazeVertex,MazeVertex>
00747             MazeVertexMap;
00748     typedef boost::associative_property_map<MazeVertexMap>
00749             PredecessorMap;
00750 
00751  public:
00757 #ifdef MSMAZES_DOX
00758     typedef unspecified StateIndex;
00759 #else
00760     typedef typename MazeGraphTraits::vertices_size_type
00761             StateIndex;
00762 #endif  /* MSMAZES_DOX */
00763 
00764  private:
00765     Pattern                  _pattern;
00766     bool                     _is_ready;
00767     bool                     _restarts_on_dead_end;
00768     MazeStructType           _maze;
00769     boost::queue<MazeVertex> _queue;
00770     MazeVertexMap            _v_map;
00771     PredecessorMap           _successor_map;
00772 
00773     FSMBuilder(const FSMBuilder& copy)
00774     {
00775     }
00776 
00777  public:
00779 
00782     FSMBuilder()
00783       : _pattern()
00784       , _is_ready(false)
00785       , _restarts_on_dead_end(false)
00786       , _maze()
00787       , _queue()
00788       , _v_map()
00789       , _successor_map(_v_map)
00790     {
00791     }
00792 
00794 
00797     virtual ~FSMBuilder()
00798     {
00799     }
00800 
00801  private:
00802     template <
00803         typename RNGEngine
00804       , typename FSMInputMaker
00805     >
00806     void _makeMazeInputs(
00807         RNGEngine& rng_engine
00808       , const FSMInputMaker& input_maker
00809       , boost::mpl::false_
00810     )
00811     {
00812         MazeGraph&
00813             maze_graph = _maze.getGraph();
00814         typename boost::property_map<MazeGraph,boost::vertex_index1_t>::type
00815             out_parent_map = boost::get(boost::vertex_index1_t(), maze_graph);
00816         typename boost::property_map<MazeGraph,boost::vertex_index2_t>::type
00817             out_source_map = boost::get(boost::vertex_index2_t(), maze_graph);
00818         typename boost::property_map<MazeGraph,boost::edge_index_t>::type
00819             edge_index_map = boost::get(boost::edge_index_t(), maze_graph);
00820         MazeVertexIterator
00821             vi, vi_end;
00822         MazeOutEdgeIterator
00823             ei, ei_end;
00824         InputIndex
00825             input;
00826         MazeVertex
00827             edge_target;
00828 
00829         for (
00830             boost::tie(vi, vi_end) = boost::vertices(maze_graph);
00831             vi != vi_end;
00832             ++vi
00833         )
00834         {
00835             boost::put(_successor_map, *vi, *vi);
00836             input = InputIndex();
00837 
00838             for (
00839                 boost::tie(ei, ei_end) = boost::out_edges(*vi, maze_graph);
00840                 ei != ei_end;
00841                 ++ei
00842             )
00843             {
00844                 edge_target = boost::target(*ei, maze_graph);
00845                 boost::put(
00846                     edge_index_map
00847                   , *ei
00848                   , (
00849                         boost::is_same<FSMInputMaker,FSMNoInputMaker>::value
00850                       ? input
00851                       : (*vi == _maze.getSourceVertex())
00852                       ? FSMInputMaker::getInput(
00853                             _pattern
00854                           , boost::get(out_source_map, edge_target)
00855                           , boost::get(out_parent_map, edge_target)
00856                           , boost::get(out_parent_map, edge_target)
00857                         )
00858                       : FSMInputMaker::getInput(
00859                             _pattern
00860                           , boost::get(out_source_map, *vi)
00861                           , boost::get(out_parent_map, *vi)
00862                           , boost::get(out_parent_map, edge_target)
00863                         )
00864                     )
00865                 );
00866                 ++input;
00867             }
00868         }
00869     }
00870 
00871     template <
00872         typename RNGEngine
00873       , typename FSMInputMaker
00874     >
00875     void _makeMazeInputs(
00876         RNGEngine& rng_engine
00877       , const FSMInputMaker& input_maker
00878       , boost::mpl::true_
00879     )
00880     {
00881         typedef boost::random_number_generator<RNGEngine,InputIndex>
00882                 Shuffler;
00883         typedef std::vector<InputIndex>
00884                 InputVector;
00885 
00886         InputVector input_vector;
00887 
00888         for (
00889             InputIndex input = InputIndex();
00890             input < _maze.getMaxOutDegree();
00891             ++input
00892         )
00893         {
00894             input_vector.push_back(input);
00895         }
00896 
00897         MazeGraph&
00898             maze_graph = _maze.getGraph();
00899         typename boost::property_map<MazeGraph,boost::edge_index_t>::type
00900             edge_index_map = boost::get(boost::edge_index_t(), maze_graph);
00901         MazeVertexIterator
00902             vi, vi_end;
00903         MazeOutEdgeIterator
00904             ei, ei_end;
00905         typename InputVector::size_type
00906             index;
00907         Shuffler
00908             shuffler(rng_engine);
00909 
00910         for (
00911             boost::tie(vi, vi_end) = boost::vertices(maze_graph);
00912             vi != vi_end;
00913             ++vi
00914         )
00915         {
00916             boost::put(_successor_map, *vi, *vi);
00917             std::random_shuffle(
00918                 input_vector.begin()
00919               , input_vector.end()
00920               , shuffler
00921             );
00922             index = typename InputVector::size_type();
00923 
00924             for (
00925                 boost::tie(ei, ei_end) = boost::out_edges(*vi, maze_graph);
00926                 ei != ei_end;
00927                 ++ei
00928             )
00929             {
00930                 boost::put(edge_index_map, *ei, input_vector[index]);
00931                 ++index;
00932             }
00933         }
00934     }
00935 
00936     void _makeSolutionMap()
00937     {
00938         typedef boost::predecessor_recorder<PredecessorMap,boost::on_tree_edge>
00939                 PredVisitor;
00940         typedef boost::bfs_visitor<std::pair<PredVisitor,boost::null_visitor> >
00941                 BFSVisitor;
00942 
00943         MazeGraph&
00944             maze_graph = _maze.getGraph();
00945         PredVisitor
00946             pred_vis(_successor_map);
00947         boost::null_visitor
00948             null_vis;
00949         BFSVisitor
00950             bfs_vis
00951               = boost::make_bfs_visitor(std::make_pair(pred_vis, null_vis));
00952 
00953         boost::breadth_first_visit(
00954             boost::make_reverse_graph(maze_graph)
00955           , _maze.getTargetVertex()
00956           , _queue
00957           , bfs_vis
00958           , boost::make_iterator_property_map(
00959                 std::vector<boost::default_color_type>(
00960                     boost::num_vertices(maze_graph)
00961                 ).begin()
00962               , boost::get(boost::vertex_index_t(), maze_graph)
00963               , boost::white_color
00964             )
00965         );
00966     }
00967 
00968  protected:
01042     template <
01043         typename RNGEngine
01044       , typename MazeMaker
01045       , typename FSMInputMaker
01046       , typename MazePolicy
01047       , typename ArgumentPack
01048     >
01049     bool
01050         initialize(
01051             RNGEngine& rng_engine
01052           , const MazeMaker& maze_maker
01053           , const FSMInputMaker& input_maker
01054           , const MazePolicy& policy
01055           , const ArgumentPack& p
01056         )
01057     {
01058         typedef typename MazeMakerTraits<MazeMaker>::RequiresRandomInputs
01059                 MazeMakerRequiresRandomInputs;
01060         typedef typename MazeMakerTraits<MazeMaker>::RestartsOnDeadEnd
01061                 MazeMakerRestartsOnDeadEnd;
01062         typedef typename MazeMakerTraits<MazeMaker>::BuildsLastVisitedMap
01063                 MazeMakerBuildsLastVisitedMap;
01064         typedef typename FSMInputMakerTraits<
01065                     FSMInputMaker
01066                 >::RequiresLastVisitedMap
01067                 FSMInputMakerRequiresLastVisitedMap;
01068 
01069         BOOST_STATIC_ASSERT(
01070             MazeMakerBuildsLastVisitedMap::value
01071          || !FSMInputMakerRequiresLastVisitedMap::value
01072         );
01073 
01074         if (
01075             ArgumentValidationPolicy::areValidArguments(
01076                 maze_maker
01077               , input_maker
01078               , policy
01079               , p
01080             )
01081         )
01082         {
01083             _is_ready = false;
01084             _pattern.initialize_with_named_params(p);
01085             MazeMaker::makeMaze(_maze, _pattern, rng_engine, policy);
01086             _maze.setMaxOutDegree(
01087                 boost::is_same<FSMInputMaker,FSMNoInputMaker>::value
01088               ? typename MazeStructType::EdgeIndex()
01089               : FSMInputMaker::getInputCount(_pattern)
01090             );
01091             _restarts_on_dead_end = MazeMakerRestartsOnDeadEnd::value;
01092             _makeMazeInputs(
01093                 rng_engine
01094               , input_maker
01095               , MazeMakerRequiresRandomInputs()
01096             );
01097             _makeSolutionMap();
01098             _is_ready = true;
01099 
01100             return true;
01101         }
01102         else
01103         {
01104             return false;
01105         }
01106     }
01107 
01113     inline const MazeStructType& getMazeStruct() const
01114     {
01115         return _maze;
01116     }
01117 
01118  public:
01124     inline const Pattern& getPattern() const
01125     {
01126         return _pattern;
01127     }
01128 
01134     inline const MazeGraph& getMazeGraph() const
01135     {
01136         return _maze.getGraph();
01137     }
01138 
01144     inline bool isReady() const
01145     {
01146         return _is_ready;
01147     }
01148 
01155     template <
01156         typename TransitionFunction
01157     >
01158     void
01159         buildTransitionFunction(
01160             TransitionFunction& transition_function
01161         ) const
01162     {
01163         if (isReady())
01164         {
01165             const MazeGraph& g           = getMazeGraph();
01166             const InputIndex input_count = _maze.getMaxOutDegree();
01167 
01168             transition_function.resize(boost::num_vertices(g), input_count);
01169 
01170             typename
01171               boost::property_map<MazeGraph,boost::vertex_index_t>::const_type
01172                 out_index_map
01173                   = boost::get(boost::vertex_index_t(), g);
01174             typename
01175               boost::property_map<MazeGraph,boost::edge_index_t>::const_type
01176                 edge_index_map
01177                   = boost::get(boost::edge_index_t(), g);
01178             const MazeVertex target = _maze.getTargetVertex();
01179 
01180             MazeVertexIterator  vi, vi_end;
01181             MazeOutEdgeIterator ei, ei_end;
01182             StateIndex          state;
01183 
01184             for (
01185                 boost::tie(vi, vi_end) = boost::vertices(g);
01186                 vi != vi_end;
01187                 ++vi
01188             )
01189             {
01190                 if (*vi != target)
01191                 {
01192                     state = boost::get(out_index_map, *vi);
01193 
01194                     for (
01195                         boost::tie(ei, ei_end) = boost::out_edges(*vi, g);
01196                         ei != ei_end;
01197                         ++ei
01198                     )
01199                     {
01200                         transition_function.setTransition(
01201                             state
01202                           , boost::get(edge_index_map, *ei)
01203                           , boost::get(out_index_map, boost::target(*ei, g))
01204                         );
01205                     }
01206 
01207                     if (_restarts_on_dead_end)
01208                     {
01209                         for (
01210                             InputIndex input = InputIndex();
01211                             input < input_count;
01212                             ++input
01213                         )
01214                         {
01215                             if (transition_function(state, input) == state)
01216                             {
01217                                 transition_function.setTransition(
01218                                     state
01219                                   , input
01220                                   , boost::get(
01221                                         out_index_map
01222                                       , _maze.getSourceVertex()
01223                                     )
01224                                 );
01225                             }
01226                         }
01227                     }
01228                 }
01229             }
01230         }
01231     }
01232 
01238     inline StateIndex getSourceState() const
01239     {
01240         return
01241             isReady()
01242           ? boost::get(
01243                 boost::get(boost::vertex_index_t(), _maze.getGraph())
01244               , _maze.getSourceVertex()
01245             )
01246           : StateIndex();
01247     }
01248 
01254     inline StateIndex getTargetState() const
01255     {
01256         return
01257             isReady()
01258           ? boost::get(
01259                 boost::get(boost::vertex_index_t(), _maze.getGraph())
01260               , _maze.getTargetVertex()
01261             )
01262           : StateIndex();
01263     }
01264 
01271     bool hasSolutionFromState(const StateIndex source_state) const
01272     {
01273         const MazeGraph& maze_graph = getMazeGraph();
01274 
01275         MazeVertex u = boost::vertex(source_state, maze_graph);
01276 
01277         while (u != boost::get(_successor_map, u))
01278         {
01279             u = boost::get(_successor_map, u);
01280         }
01281 
01282         return u == _maze.getTargetVertex();
01283     }
01284 
01290     InputIndex getCorrectInput(const StateIndex source_state) const
01291     {
01292         const MazeGraph& maze_graph = getMazeGraph();
01293         const MazeVertex u = boost::vertex(source_state, maze_graph);
01294         const MazeVertex v = boost::get(_successor_map, u);
01295 
01296         typename boost::property_map<MazeGraph,boost::edge_index_t>::const_type
01297             edge_index_map = boost::get(boost::edge_index_t(), maze_graph);
01298 
01299         MazeOutEdgeIterator ei, ei_end;
01300 
01301         for (
01302             boost::tie(ei, ei_end) = boost::out_edges(u, maze_graph);
01303             ei != ei_end;
01304             ++ei
01305         )
01306         {
01307             if (boost::target(*ei, maze_graph) == v)
01308             {
01309                 return boost::get(edge_index_map, *ei);
01310             }
01311         }
01312 
01313         return _maze.getMaxOutDegree();
01314     }
01315 
01321     const Cell& getStateCell(const StateIndex state) const
01322     {
01323         const MazeGraph& maze_graph = getMazeGraph();
01324         const MazeVertex v          = boost::vertex(state, maze_graph);
01325 
01326         return
01327             (v == _maze.getSourceVertex())
01328           ? _pattern.getEntranceCell()
01329           : (v == _maze.getTargetVertex())
01330           ? _pattern.getExitCell()
01331           : _pattern.getCell(
01332                 boost::get(boost::get(boost::vertex_index1_t(), maze_graph), v)
01333             );
01334     }
01335 
01342     Direction getStateDirection(const StateIndex state) const
01343     {
01344         const MazeGraph& maze_graph = getMazeGraph();
01345         const MazeVertex v          = boost::vertex(state, maze_graph);
01346 
01347         return
01348             _pattern.getEdgeDirection(
01349                 boost::get(boost::get(boost::vertex_index2_t(), maze_graph), v)
01350               , boost::get(boost::get(boost::vertex_index1_t(), maze_graph), v)
01351             );
01352     }
01353 };
01354 }  // namespace msmazes
01355 
01356 #endif  /* MSMAZES_CORE_FSM_BUILDER_HPP */

Multi-State Mazes in C++ is hosted by SourceForge.net. Use the Table of Contents for navigation.