maker_walkthrough.hpp

Go to the documentation of this file.
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 SourceForge.net. Use the Table of Contents for navigation.