alfps

C curve + "++"

Apr 5th, 2021
1,398
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.92 KB | None | 0 0
  1. #include <kickstart/all.hpp>        // https://github.com/alf-p-steinbach/kickstart
  2. using namespace kickstart::all;     // ascii::*, math::*, two_d_grid::*, out, endl
  3.  
  4. #include <bitset>
  5. namespace box_drawing {
  6.     using std::bitset;
  7.  
  8.     using Position  = two_d_grid::Position;
  9.     using Size      = two_d_grid::Size;
  10.    
  11.     //---------------------------------------------- Direction
  12.     struct Direction{ enum Enum{ right, up, left, down, N }; };
  13.     using Dir = Direction;
  14.     static_assert( Dir::N == 4 );
  15.    
  16.     constexpr auto unit_offset_for( const Direction::Enum dir )
  17.         -> Size
  18.     { return array<Size, Dir::N>{{ {1, 0}, {0, -1}, {-1, 0}, {0, 1} }}[dir]; }
  19.  
  20.     constexpr auto opposite_of( const Direction::Enum dir )
  21.         -> Direction::Enum
  22.     { return array{ Dir::left, Dir::down, Dir::right, Dir::up }[dir]; }
  23.  
  24.     constexpr auto left_from( const Direction::Enum dir )
  25.         -> Direction::Enum
  26.     { return Direction::Enum( (dir + 1) % Direction::N ); }
  27.  
  28.     constexpr auto right_from( const Direction::Enum dir )
  29.         -> Direction::Enum
  30.     { return Direction::Enum( (dir - 1 + Direction::N) % Direction::N ); }
  31.  
  32.     //---------------------------------------------- Lines_in_box
  33.     using Lines_in_box = bitset<Direction::N>;
  34.     constexpr int n_box_states = math::intpow( 2, Direction::N );
  35.  
  36.     auto line_char( const Lines_in_box box_lines )
  37.         -> string_view
  38.     {
  39.         static const array<string_view, n_box_states> the_chars =
  40.         {
  41.             " ", "╶", "╵", "└", "╴", "─", "┘", "┴", "╷", "┌", "│", "├", "┐", "┬", "┤", "┼"
  42.         };
  43.         return the_chars[box_lines.to_ulong()];
  44.     }
  45.    
  46.     //---------------------------------------------- Canvas
  47.     class Canvas
  48.     {
  49.         Matrix_<Lines_in_box>   m_boxes;
  50.        
  51.     public:
  52.         Canvas( const Size size ): m_boxes( size ) {}
  53.        
  54.         auto contains( const Position& p ) const
  55.             -> bool
  56.         {
  57.             const Size s = m_boxes.size();
  58.             return (0 <= p.x and p.x < s.w and 0 <= p.y and p.y < s.h);
  59.         }
  60.  
  61.         auto unit_line( const Position start_point, const Direction::Enum dir )
  62.             -> Position
  63.         {
  64.             const auto end_point = start_point + unit_offset_for( dir );
  65.             if( contains( start_point ) ) {
  66.                 m_boxes( start_point ).set( dir );  // Set bit
  67.             }
  68.             if( contains( end_point ) ) {
  69.                 m_boxes( end_point ).set( opposite_of( dir ) );
  70.             }
  71.             return end_point;
  72.         }
  73.  
  74.         auto line( const Position start_point, const Direction::Enum dir, const int length )
  75.             -> Position
  76.         {
  77.             Position where = start_point;
  78.             for( int i = 1; i <= length; ++i ) {
  79.                 where = unit_line( where, dir );
  80.             }
  81.             return where;
  82.         }
  83.  
  84.         auto widened() const
  85.             -> Canvas
  86.         {
  87.             auto result = Canvas( Size{ 2*m_boxes.width() + 1, m_boxes.height() } );
  88.             for( int y = 0, h = m_boxes.height(); y < h; ++y ) {
  89.                 Lines_in_box previous;
  90.                 for( int x = 0, w = m_boxes.width(); x <= w; ++x ) {
  91.                     auto& filler = result.m_boxes({2*x, y});
  92.                     if( previous[Direction::right] ) { filler.set( Direction::left ); }
  93.                     if( x < w ) {
  94.                         auto& current = result.m_boxes({1 + 2*x, y});
  95.                         current = m_boxes({x, y});
  96.                         if( current[Direction::left] ) { filler.set( Direction::right ); }
  97.                         previous = current;
  98.                     }
  99.                 }
  100.             }
  101.             return result;
  102.         }
  103.  
  104.         auto to_full_string() const
  105.             -> string
  106.         {
  107.             string result;
  108.             for( int y = 0, h = m_boxes.height(); y < h; ++y ) {
  109.                 for( int x = 0, w = m_boxes.width(); x < w; ++x ) {
  110.                     result += line_char( m_boxes( x, y ).to_ulong() );
  111.                 }
  112.                 result += '\n';
  113.             }
  114.             return result;
  115.         }
  116.        
  117.         auto to_string() const
  118.             -> string
  119.         { return ascii::suffixtrimmed_string( to_full_string() ) + "\n"; }
  120.     };
  121. }  // namespace box_drawing
  122.  
  123. using Position  = two_d_grid::Position;
  124. using Direction = box_drawing::Direction;   // right, up, left, down
  125.  
  126. class C_curve
  127. {
  128.     box_drawing::Canvas&    m_canvas;
  129.  
  130. public:
  131.     C_curve( box_drawing::Canvas& canvas ): m_canvas( canvas ) {}
  132.    
  133.     void draw( Position& where, const Direction::Enum direction, const int level )
  134.     {
  135.         if( level == 0 ) {
  136.             where = m_canvas.unit_line( where, direction ); // Returns line end point.
  137.         } else {
  138.             draw( where, direction, level - 1 );
  139.             draw( where, left_from( direction ), level - 1 );
  140.         }
  141.     }
  142.  
  143.     void draw( const Position& start_pos, const Direction::Enum direction, const int level )
  144.     {
  145.         Position where = start_pos;
  146.         draw( where, direction, level );
  147.     }
  148. };
  149.  
  150. void draw_plus_sign( box_drawing::Canvas& canvas, const Position& start_point, const int size )
  151. {
  152.     Position            where   = start_point;
  153.     Direction::Enum     dir     = Direction::right;
  154.  
  155.     for( int i = 1; i <= 4; ++i ) {
  156.         where = canvas.line( where, dir, size );
  157.         dir = right_from( dir );
  158.         where = canvas.line( where, dir, size );
  159.         dir = left_from( dir );
  160.         where = canvas.line( where, dir, size );
  161.         dir = right_from( dir );
  162.     }        
  163. }
  164.  
  165. auto main() -> int
  166. {
  167.     auto drawing = box_drawing::Canvas({40 + 20, 64});
  168.  
  169.     C_curve( drawing ).draw( {31, 15}, Direction::left, 10 );
  170.     draw_plus_sign( drawing, {34, 21}, 7 );
  171.     draw_plus_sign( drawing, {42, 20}, 7 );
  172.     out << drawing.widened().to_string() << endl;   // "widened": 2x width for console display.
  173. }
  174.  
Advertisement
Comments
Add Comment
Please, Sign In to add comment