@ -7,216 +7,221 @@
using std : : string ;
using matrix : : Matrix ;
inline size_t rand ( size_t i , size_t j ) {
if ( i < j ) {
return Random : : uniform ( i , j ) ;
} else if ( j < i ) {
return Random : : uniform ( j , i ) ;
} else {
return i ;
namespace maze {
inline size_t rand ( size_t i , size_t j ) {
if ( i < j ) {
return Random : : uniform ( i , j ) ;
} else if ( j < i ) {
return Random : : uniform ( j , i ) ;
} else {
return i ;
}
}
}
inline bool complete ( Matrix & maze ) {
size_t width = matrix : : width ( maze ) ;
size_t height = matrix : : height ( maze ) ;
inline bool complete ( Matrix & maze ) {
size_t width = matrix : : width ( maze ) ;
size_t height = matrix : : height ( maze ) ;
for ( size_t row = 1 ; row < height ; row + = 2 ) {
for ( size_t col = 1 ; col < width ; col + = 2 ) {
if ( maze [ row ] [ col ] ! = 0 ) return false ;
for ( size_t row = 1 ; row < height ; row + = 2 ) {
for ( size_t col = 1 ; col < width ; col + = 2 ) {
if ( maze [ row ] [ col ] ! = 0 ) return false ;
}
}
}
return true ;
}
return true ;
}
std : : vector < Point > neighborsAB ( Matrix & maze , Point on ) {
std : : vector < Point > result ;
std : : vector < Point > neighborsAB ( Matrix & maze , Point on ) {
std : : vector < Point > result ;
std : : array < Point , 4 > points { {
{ on . x , on . y - 2 } ,
{ on . x , on . y + 2 } ,
{ on . x - 2 , on . y } ,
{ on . x + 2 , on . y }
} } ;
std : : array < Point , 4 > points { {
{ on . x , on . y - 2 } ,
{ on . x , on . y + 2 } ,
{ on . x - 2 , on . y } ,
{ on . x + 2 , on . y }
} } ;
for ( auto point : points ) {
if ( matrix : : inbounds ( maze , point . x , point . y ) ) {
result . push_back ( point ) ;
for ( auto point : points ) {
if ( matrix : : inbounds ( maze , point . x , point . y ) ) {
result . push_back ( point ) ;
}
}
}
return result ;
}
return result ;
}
std : : vector < Point > neighbors ( Matrix & maze , Point on ) {
std : : vector < Point > result ;
std : : vector < Point > neighbors ( Matrix & maze , Point on ) {
std : : vector < Point > result ;
std : : array < Point , 4 > points { {
{ on . x , on . y - 2 } ,
{ on . x , on . y + 2 } ,
{ on . x - 2 , on . y } ,
{ on . x + 2 , on . y }
} } ;
std : : array < Point , 4 > points { {
{ on . x , on . y - 2 } ,
{ on . x , on . y + 2 } ,
{ on . x - 2 , on . y } ,
{ on . x + 2 , on . y }
} } ;
for ( auto point : points ) {
if ( matrix : : inbounds ( maze , point . x , point . y ) ) {
if ( maze [ point . y ] [ point . x ] = = WALL_VALUE ) {
result . push_back ( point ) ;
for ( auto point : points ) {
if ( matrix : : inbounds ( maze , point . x , point . y ) ) {
if ( maze [ point . y ] [ point . x ] = = WALL_VALUE ) {
result . push_back ( point ) ;
}
}
}
}
return result ;
}
return result ;
}
inline std : : pair < Point , Point > find_coord ( Matrix & maze ) {
size_t width = matrix : : width ( maze ) ;
size_t height = matrix : : height ( maze ) ;
inline std : : pair < Point , Point > find_coord ( Matrix & maze ) {
size_t width = matrix : : width ( maze ) ;
size_t height = matrix : : height ( maze ) ;
for ( size_t y = 1 ; y < height ; y + = 2 ) {
for ( size_t x = 1 ; x < width ; x + = 2 ) {
if ( maze [ y ] [ x ] = = WALL_VALUE ) {
auto found = neighborsAB ( maze , { x , y } ) ;
for ( size_t y = 1 ; y < height ; y + = 2 ) {
for ( size_t x = 1 ; x < width ; x + = 2 ) {
if ( maze [ y ] [ x ] = = WALL_VALUE ) {
auto found = neighborsAB ( maze , { x , y } ) ;
for ( auto point : found ) {
if ( maze [ point . y ] [ point . x ] = = 0 ) {
return { { x , y } , point } ;
for ( auto point : found ) {
if ( maze [ point . y ] [ point . x ] = = 0 ) {
return { { x , y } , point } ;
}
}
}
}
}
}
matrix : : dump ( " BAD MAZE " , maze ) ;
dbc : : sentinel ( " failed to find coord? " ) ;
}
matrix : : dump ( " BAD MAZE " , maze ) ;
dbc : : sentinel ( " failed to find coord? " ) ;
}
void maze : : randomize_rooms ( std : : vector < Room > & rooms_out , std : : vector < Point > & maybe_here ) {
dbc : : check ( maybe_here . size ( ) > = 2 , " must have at least two possible points to place rooms " ) ;
void Builder : : randomize_rooms ( ) {
dbc : : check ( $ dead_ends . size ( ) > = 2 , " must have at least two possible points to place rooms " ) ;
while ( rooms_out . size ( ) < 2 ) {
// use those dead ends to randomly place rooms
for ( auto at : maybe_here ) {
if ( Random : : uniform ( 0 , 1 ) ) {
size_t offset = Random : : uniform ( 0 , 1 ) ;
Room cur { at . x + offset , at . y + offset , 1 , 1 } ;
rooms_out . push_back ( cur ) ;
while ( $ rooms . size ( ) < 2 ) {
// use those dead ends to randomly place rooms
for ( auto at : $ dead_ends ) {
if ( Random : : uniform ( 0 , 1 ) ) {
size_t offset = Random : : uniform ( 0 , 1 ) ;
Room cur { at . x + offset , at . y + offset , 1 , 1 } ;
$ rooms . push_back ( cur ) ;
}
}
}
}
}
void maze : : init ( Matrix & maze ) {
matrix : : assign ( maze , WALL_VALUE ) ;
}
void maze : : divide ( Matrix & maze , Point start , Point end ) {
for ( matrix : : line it { start , end } ; it . next ( ) ; ) {
maze [ it . y ] [ it . x ] = 0 ;
maze [ it . y + 1 ] [ it . x ] = 0 ;
void Builder : : init ( ) {
matrix : : assign ( $ walls , WALL_VALUE ) ;
}
}
void maze : : hunt_and_kill ( Matrix & maze , std : : vector < Room > & rooms , std : : vector < Point > & dead_ends ) {
for ( auto & room : rooms ) {
for ( matrix : : box it { maze , room . x , room . y , room . width } ; it . next ( ) ; ) {
maze [ it . y ] [ it . x ] = 0 ;
void Builder : : divide ( Point start , Point end ) {
for ( matrix : : line it { start , end } ; it . next ( ) ; ) {
$ walls [ it . y ] [ it . x ] = 0 ;
$ walls [ it . y + 1 ] [ it . x ] = 0 ;
}
}
Point on { 1 , 1 } ;
while ( ! complete ( maze ) ) {
auto n = neighbors ( maze , on ) ;
if ( n . size ( ) = = 0 ) {
dead_ends . push_back ( on ) ;
auto t = find_coord ( maze ) ;
on = t . first ;
maze [ on . y ] [ on . x ] = 0 ;
size_t row = ( on . y + t . second . y ) / 2 ;
size_t col = ( on . x + t . second . x ) / 2 ;
maze [ row ] [ col ] = 0 ;
} else {
auto nb = n [ rand ( size_t ( 0 ) , n . size ( ) - 1 ) ] ;
maze [ nb . y ] [ nb . x ] = 0 ;
void Builder : : hunt_and_kill ( ) {
for ( auto & room : $ rooms ) {
for ( matrix : : box it { $ walls , room . x , room . y , room . width } ; it . next ( ) ; ) {
$ walls [ it . y ] [ it . x ] = 0 ;
}
}
size_t row = ( nb . y + on . y ) / 2 ;
size_t col = ( nb . x + on . x ) / 2 ;
maze [ row ] [ col ] = 0 ;
on = nb ;
Point on { 1 , 1 } ;
while ( ! complete ( $ walls ) ) {
auto n = neighbors ( $ walls , on ) ;
if ( n . size ( ) = = 0 ) {
$ dead_ends . push_back ( on ) ;
auto t = find_coord ( $ walls ) ;
on = t . first ;
$ walls [ on . y ] [ on . x ] = 0 ;
size_t row = ( on . y + t . second . y ) / 2 ;
size_t col = ( on . x + t . second . x ) / 2 ;
$ walls [ row ] [ col ] = 0 ;
} else {
auto nb = n [ rand ( size_t ( 0 ) , n . size ( ) - 1 ) ] ;
$ walls [ nb . y ] [ nb . x ] = 0 ;
size_t row = ( nb . y + on . y ) / 2 ;
size_t col = ( nb . x + on . x ) / 2 ;
$ walls [ row ] [ col ] = 0 ;
on = nb ;
}
}
}
for ( auto at : dead_ends ) {
for ( auto & room : rooms ) {
Point room_ul { room . x - room . width - 1 , room . y - room . height - 1 } ;
Point room_lr { room . x + room . width - 1 , room . y + room . height - 1 } ;
if ( at . x > = room_ul . x & & at . y > = room_ul . y & &
at . x < = room_lr . x & & at . y < = room_lr . y )
{
for ( matrix : : compass it { maze , at . x , at . y } ; it . next ( ) ; ) {
if ( maze [ it . y ] [ it . x ] = = 1 ) {
maze [ it . y ] [ it . x ] = 0 ;
break ;
for ( auto at : $ dead_ends ) {
for ( auto & room : $ rooms ) {
Point room_ul { room . x - room . width - 1 , room . y - room . height - 1 } ;
Point room_lr { room . x + room . width - 1 , room . y + room . height - 1 } ;
if ( at . x > = room_ul . x & & at . y > = room_ul . y & &
at . x < = room_lr . x & & at . y < = room_lr . y )
{
for ( matrix : : compass it { $ walls , at . x , at . y } ; it . next ( ) ; ) {
if ( $ walls [ it . y ] [ it . x ] = = 1 ) {
$ walls [ it . y ] [ it . x ] = 0 ;
break ;
}
}
}
}
}
}
}
void maze : : inner_donut ( Matrix & maze , float outer_rad , float inner_rad ) {
size_t x = matrix : : width ( maze ) / 2 ;
size_t y = matrix : : height ( maze ) / 2 ;
void Builder : : inner_donut ( float outer_rad , float inner_rad ) {
size_t x = matrix : : width ( $ walls ) / 2 ;
size_t y = matrix : : height ( $ walls ) / 2 ;
for ( matrix : : circle it { maze , { x , y } , outer_rad } ;
it . next ( ) ; )
{
for ( int x = it . left ; x < it . right ; x + + ) {
maze [ it . y ] [ x ] = 0 ;
for ( matrix : : circle it { $ walls , { x , y } , outer_rad } ;
it . next ( ) ; )
{
for ( int x = it . left ; x < it . right ; x + + ) {
$ walls [ it . y ] [ x ] = 0 ;
}
}
}
for ( matrix : : circle it { maze , { x , y } , inner_rad } ;
it . next ( ) ; )
{
for ( int x = it . left ; x < it . right ; x + + ) {
maze [ it . y ] [ x ] = 1 ;
for ( matrix : : circle it { $ walls , { x , y } , inner_rad } ;
it . next ( ) ; )
{
for ( int x = it . left ; x < it . right ; x + + ) {
$ walls [ it . y ] [ x ] = 1 ;
}
}
}
}
void maze : : inner_box ( Matrix & maze , size_t outer_size , size_t inner_size ) {
void Builder : : inner_box ( size_t outer_size , size_t inner_size ) {
size_t x = matrix : : width ( $ walls ) / 2 ;
size_t y = matrix : : height ( $ walls ) / 2 ;
size_t x = matrix : : width ( maze ) / 2 ;
size_t y = matrix : : height ( maze ) / 2 ;
for ( matrix : : box it { maze , x , y , outer_size } ;
it . next ( ) ; )
{
maze [ it . y ] [ it . x ] = 0 ;
}
for ( matrix : : box it { $ walls , x , y , outer_size } ;
it . next ( ) ; )
{
$ walls [ it . y ] [ it . x ] = 0 ;
}
for ( matrix : : box it { maze , x , y , inner_size } ;
it . next ( ) ; )
{
maze [ it . y ] [ it . x ] = 1 ;
for ( matrix : : box it { $ walls , x , y , inner_size } ;
it . next ( ) ; )
{
$ walls [ it . y ] [ it . x ] = 1 ;
}
}
}
void maze : : remove_dead_ends ( Matrix & maze , std : : vector < Point > & dead_ends ) {
for ( auto at : dead_ends ) {
for ( matrix : : compass it { maze , at . x , at . y } ; it . next ( ) ; ) {
if ( maze [ it . y ] [ it . x ] = = 0 ) {
int diff_x = at . x - it . x ;
int diff_y = at . y - it . y ;
maze [ at . y + diff_y ] [ at . x + diff_x ] = 0 ;
void Builder : : remove_dead_ends ( ) {
dbc : : check ( $ dead_ends . size ( ) > 0 , " you have to run an algo first, no dead_ends to remove " ) ;
for ( auto at : $ dead_ends ) {
for ( matrix : : compass it { $ walls , at . x , at . y } ; it . next ( ) ; ) {
if ( $ walls [ it . y ] [ it . x ] = = 0 ) {
int diff_x = at . x - it . x ;
int diff_y = at . y - it . y ;
$ walls [ at . y + diff_y ] [ at . x + diff_x ] = 0 ;
}
}
}
}
void Builder : : dump ( const std : : string & msg ) {
matrix : : dump ( msg , $ walls ) ;
}
}