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 . Use the Table of Contents for navigation.