00001 00029 #ifndef MSMAZES_CORE_MAZE_MAKER_WALKTHROUGH_HPP 00030 #define MSMAZES_CORE_MAZE_MAKER_WALKTHROUGH_HPP 00031 00032 // std::list 00033 #include <list> 00034 // std::vector 00035 #include <vector> 00036 // std::map 00037 #include <map> 00038 // std::random_shuffle 00039 #include <algorithm> 00040 // boost::is_same 00041 #include <boost/type_traits/is_same.hpp> 00042 // boost::mpl::true_ and boost::mpl::false_ 00043 #include <boost/mpl/bool.hpp> 00044 // boost::tie 00045 #include <boost/utility.hpp> 00046 // boost::random_number_generator 00047 #include <boost/random/random_number_generator.hpp> 00048 // boost::property_map, boost::associative_property_map, 00049 // boost::get, and boost::put 00050 #include <boost/property_map.hpp> 00051 // boost::graph_traits 00052 #include <boost/graph/graph_traits.hpp> 00053 //#include <boost/graph/adjacency_list.hpp> must be included before this file. 00054 // msmazes::makePath and msmazes::makeRandomPaths 00055 #include <msmazes/core/graph/path_utility.hpp> 00056 // msmazes::removeCrossEdges 00057 #include <msmazes/core/graph/remove_cross_edges.hpp> 00058 00059 namespace msmazes { 00060 00065 struct SimpleWalkthroughMazePolicy 00066 { 00067 template < 00068 typename Pattern 00069 , typename CellIndex 00070 > 00071 static bool 00072 shouldAddEdge( 00073 const Pattern& pattern 00074 , const CellIndex source_index 00075 , const CellIndex parent_index 00076 , const CellIndex target_index 00077 ) 00078 { 00079 return true; 00080 } 00081 }; 00082 00087 struct NoNegativeTurnWalkthroughMazePolicy 00088 { 00089 template < 00090 typename Pattern 00091 , typename CellIndex 00092 > 00093 static bool 00094 shouldAddEdge( 00095 const Pattern& pattern 00096 , const CellIndex source_index 00097 , const CellIndex parent_index 00098 , const CellIndex target_index 00099 ) 00100 { 00101 if (source_index == parent_index) 00102 { 00103 return 00104 pattern.getYawTurn(source_index, parent_index, target_index) 00105 == 0; 00106 } 00107 else 00108 { 00109 return 00110 pattern.getYawTurn(source_index, parent_index, target_index) 00111 >= 0; 00112 } 00113 } 00114 }; 00115 00117 00141 struct WalkthroughMazeMaker 00142 { 00146 typedef SimpleWalkthroughMazePolicy 00147 DefaultPolicy; 00148 00152 typedef boost::mpl::false_ 00153 RequiresRandomInputs; 00154 00159 typedef boost::mpl::false_ 00160 RestartsOnDeadEnd; 00161 00166 typedef boost::mpl::true_ 00167 BuildsLastVisitedMap; 00168 00179 template < 00180 typename MazeStructType 00181 , typename Pattern 00182 , typename RNGEngine 00183 , typename MazePolicy 00184 > 00185 static void 00186 makeMaze( 00187 MazeStructType& maze 00188 , const Pattern& pattern 00189 , RNGEngine& rng_engine 00190 , const MazePolicy& policy 00191 ) 00192 { 00193 typedef typename Pattern::Cell 00194 Cell; 00195 typedef typename Pattern::CellEqualityPolicy 00196 CellEqualityPolicy; 00197 typedef typename Pattern::Graph 00198 BaseGraph; 00199 typedef boost::graph_traits<BaseGraph> 00200 BaseGraphTraits; 00201 typedef typename BaseGraphTraits::vertices_size_type 00202 BaseIndex; 00203 typedef typename BaseGraphTraits::vertex_descriptor 00204 BaseVertex; 00205 typedef typename MazeStructType::Graph 00206 MazeGraph; 00207 typedef boost::graph_traits<MazeGraph> 00208 MazeGraphTraits; 00209 typedef typename MazeGraphTraits::vertices_size_type 00210 MazeIndex; 00211 typedef typename MazeGraphTraits::vertex_descriptor 00212 MazeVertex; 00213 typedef std::vector<MazeVertex> 00214 MazeVertexVector; 00215 typedef std::map<MazeVertex,MazeVertex> 00216 MazeVertexMap; 00217 typedef boost::associative_property_map<MazeVertexMap> 00218 PredecessorMap; 00219 typedef boost::random_number_generator<RNGEngine,BaseIndex> 00220 Shuffler; 00221 typedef std::list<MazeVertex> 00222 Path; 00223 00224 const BaseGraph& base_graph = pattern.getGraph(); 00225 MazeGraph& maze_graph = maze.getGraph(); 00226 BaseIndex base_vertex_count = boost::num_vertices(base_graph); 00227 BaseVertex source = BaseGraphTraits::null_vertex(); 00228 BaseVertex target = BaseGraphTraits::null_vertex(); 00229 Shuffler shuffler(rng_engine); 00230 typename Path::size_type min_path_length = base_vertex_count >> 1; 00231 00232 maze.setSourceVertex(MazeGraphTraits::null_vertex()); 00233 maze.setTargetVertex(MazeGraphTraits::null_vertex()); 00234 00235 if ( 00236 boost::is_same< 00237 MazePolicy 00238 , NoNegativeTurnWalkthroughMazePolicy 00239 >::value 00240 ) 00241 { 00242 ++min_path_length; 00243 } 00244 else 00245 { 00246 min_path_length += base_vertex_count; 00247 } 00248 00249 const Cell& src_cell = pattern.getSourceCell(); 00250 const Cell& tgt_cell = pattern.getTargetCell(); 00251 00252 MazeIndex 00253 maze_vertex_count = 3; 00254 typename boost::property_map<BaseGraph,boost::vertex_index_t>::type 00255 in_index_map = boost::get(boost::vertex_index_t(), base_graph); 00256 typename BaseGraphTraits::vertex_iterator 00257 in_vi, in_vend; 00258 CellEqualityPolicy 00259 are_equal_cells; 00260 00261 for ( 00262 boost::tie(in_vi, in_vend) = boost::vertices(base_graph); 00263 in_vi != in_vend; 00264 ++in_vi 00265 ) 00266 { 00267 const Cell& 00268 cell = pattern.getCell(boost::get(in_index_map, *in_vi)); 00269 00270 if (are_equal_cells(cell, src_cell)) 00271 { 00272 source = *in_vi; 00273 } 00274 00275 if (are_equal_cells(cell, tgt_cell)) 00276 { 00277 target = *in_vi; 00278 } 00279 00280 maze_vertex_count += boost::out_degree(*in_vi, base_graph); 00281 } 00282 00283 while (boost::num_vertices(maze_graph) < maze_vertex_count) 00284 { 00285 boost::add_vertex(maze_graph); 00286 } 00287 00288 MazeIndex 00289 vertex_count = boost::num_vertices(maze_graph); 00290 MazeVertex 00291 out_vertex = MazeGraphTraits::null_vertex(); 00292 00293 while (vertex_count > maze_vertex_count) 00294 { 00295 out_vertex = boost::vertex(--vertex_count, maze_graph); 00296 boost::clear_vertex(out_vertex, maze_graph); 00297 boost::remove_vertex(out_vertex, maze_graph); 00298 } 00299 00300 typename boost::property_map<MazeGraph,boost::vertex_index1_t>::type 00301 out_parent_map = boost::get(boost::vertex_index1_t(), maze_graph); 00302 typename boost::property_map<MazeGraph,boost::vertex_index2_t>::type 00303 out_source_map = boost::get(boost::vertex_index2_t(), maze_graph); 00304 typename MazeGraphTraits::vertex_iterator 00305 out_vi, out_vend; 00306 00307 boost::tie(out_vi, out_vend) = boost::vertices(maze_graph); 00308 maze.setSourceVertex(*out_vi); 00309 boost::clear_vertex(*out_vi, maze_graph); 00310 00311 const MazeVertex true_source = *(++out_vi); 00312 BaseIndex source_index = boost::get(in_index_map, source); 00313 00314 boost::clear_vertex(true_source, maze_graph); 00315 boost::put(out_parent_map, true_source, source_index); 00316 boost::put(out_source_map, true_source, source_index); 00317 boost::put(out_parent_map, maze.getSourceVertex(), source_index); 00318 boost::put(out_source_map, maze.getSourceVertex(), source_index); 00319 boost::add_edge(maze.getSourceVertex(), true_source, maze_graph); 00320 00321 std::vector<MazeVertexVector> vertex_vector(base_vertex_count); 00322 BaseVertex parent_vertex = BaseGraphTraits::null_vertex(); 00323 BaseIndex parent_index; 00324 typename BaseGraphTraits::adjacency_iterator in_ai, in_aend; 00325 00326 for ( 00327 boost::tie(in_vi, in_vend) = boost::vertices(base_graph); 00328 in_vi != in_vend; 00329 ++in_vi 00330 ) 00331 { 00332 parent_vertex = *in_vi; 00333 parent_index = boost::get(in_index_map, parent_vertex); 00334 00335 for ( 00336 boost::tie(in_ai, in_aend) 00337 = boost::adjacent_vertices(parent_vertex, base_graph); 00338 in_ai != in_aend; 00339 ++in_ai 00340 ) 00341 { 00342 out_vertex = *(++out_vi); 00343 boost::clear_vertex(out_vertex, maze_graph); 00344 source_index = boost::get(in_index_map, *in_ai); 00345 boost::put(out_parent_map, out_vertex, parent_index); 00346 boost::put(out_source_map, out_vertex, source_index); 00347 vertex_vector[source_index].push_back(out_vertex); 00348 } 00349 } 00350 00351 maze.setTargetVertex(*(++out_vi)); 00352 source_index = boost::get(in_index_map, target); 00353 vertex_vector[source_index].push_back(*out_vi); 00354 boost::clear_vertex(*out_vi, maze_graph); 00355 boost::put(out_parent_map, *out_vi, base_vertex_count); 00356 boost::put(out_source_map, *out_vi, source_index); 00357 00358 MazeVertex in_vertex; 00359 BaseIndex target_index; 00360 typename MazeVertexVector::iterator child_i, child_end; 00361 00362 for ( 00363 boost::tie(out_vi, out_vend) = boost::vertices(maze_graph); 00364 out_vi != out_vend; 00365 ++out_vi 00366 ) 00367 { 00368 in_vertex = *out_vi; 00369 00370 if ( 00371 (in_vertex != maze.getSourceVertex()) 00372 && (in_vertex != maze.getTargetVertex()) 00373 ) 00374 { 00375 parent_index = boost::get(out_parent_map, in_vertex); 00376 source_index = boost::get(out_source_map, in_vertex); 00377 00378 MazeVertexVector& v_vector = vertex_vector[parent_index]; 00379 00380 std::random_shuffle(v_vector.begin(), v_vector.end(), shuffler); 00381 child_end = v_vector.end(); 00382 00383 for ( 00384 child_i = v_vector.begin(); 00385 child_i != child_end; 00386 ++child_i 00387 ) 00388 { 00389 out_vertex = *child_i; 00390 target_index = boost::get(out_parent_map, out_vertex); 00391 00392 if ( 00393 (target_index != source_index) 00394 && MazePolicy::shouldAddEdge( 00395 pattern 00396 , source_index 00397 , parent_index 00398 , target_index 00399 ) 00400 ) 00401 { 00402 boost::add_edge(in_vertex, out_vertex, maze_graph); 00403 } 00404 } 00405 } 00406 } 00407 00408 MazeVertexMap v_map; 00409 PredecessorMap p_map(v_map); 00410 Path path; 00411 00412 while (path.empty()) 00413 { 00414 makeRandomPaths( 00415 input_graph_arg = maze_graph 00416 , source_vertex_arg = true_source 00417 , shuffler_arg = shuffler 00418 , output_predecessor_map_arg = p_map 00419 ); 00420 00421 if ( 00422 !makePath( 00423 true_source 00424 , maze.getTargetVertex() 00425 , p_map 00426 , path 00427 ) 00428 || (path.size() < min_path_length) 00429 ) 00430 { 00431 path.clear(); 00432 } 00433 } 00434 00435 removeCrossEdges( 00436 path_begin_arg = path.begin() 00437 , path_end_arg = path.end() 00438 , input_graph_arg = maze_graph 00439 ); 00440 } 00441 }; 00442 } // namespace msmazes 00443 00444 #endif /* MSMAZES_CORE_MAZE_MAKER_WALKTHROUGH_HPP */
Multi-State Mazes in C++ is hosted by . Use the Table of Contents for navigation.