void shadowcasting_runoff(int iterations, bool test_bresenham = false ) { // Construct a rng that produces integers in a range selected to provide the probability // we want, i.e. if we want 1/4 tiles to be set, produce numbers in the range 0-3, // with 0 indicating the bit is set. const unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); std::default_random_engine generator(seed); std::uniform_int_distribution<unsigned int> distribution(0, DENOMINATOR); auto rng = std::bind ( distribution, generator ); float seen_squares_control[MAPSIZE*SEEX][MAPSIZE*SEEY] = {{0}}; float seen_squares_experiment[MAPSIZE*SEEX][MAPSIZE*SEEY] = {{0}}; float transparency_cache[MAPSIZE*SEEX][MAPSIZE*SEEY] = {{0}}; // Initialize the transparency value of each square to a random value. for( auto &inner : transparency_cache ) { for( float &square : inner ) { if( rng() < NUMERATOR ) { square = LIGHT_TRANSPARENCY_SOLID; } else { square = LIGHT_TRANSPARENCY_CLEAR; } } } map dummy; const int offsetX = 65; const int offsetY = 65; auto start1 = std::chrono::high_resolution_clock::now(); for( int i = 0; i < iterations; i++ ) { // First the control algorithm. oldCastLight( seen_squares_control, transparency_cache, 0, 1, 1, 0, offsetX, offsetY, 0 ); oldCastLight( seen_squares_control, transparency_cache, 1, 0, 0, 1, offsetX, offsetY, 0 ); oldCastLight( seen_squares_control, transparency_cache, 0, -1, 1, 0, offsetX, offsetY, 0 ); oldCastLight( seen_squares_control, transparency_cache, -1, 0, 0, 1, offsetX, offsetY, 0 ); oldCastLight( seen_squares_control, transparency_cache, 0, 1, -1, 0, offsetX, offsetY, 0 ); oldCastLight( seen_squares_control, transparency_cache, 1, 0, 0, -1, offsetX, offsetY, 0 ); oldCastLight( seen_squares_control, transparency_cache, 0, -1, -1, 0, offsetX, offsetY, 0 ); oldCastLight( seen_squares_control, transparency_cache, -1, 0, 0, -1, offsetX, offsetY, 0 ); } auto end1 = std::chrono::high_resolution_clock::now(); auto start2 = std::chrono::high_resolution_clock::now(); for( int i = 0; i < iterations; i++ ) { // Then the current algorithm. castLight<0, 1, 1, 0, sight_calc, sight_check>( seen_squares_experiment, transparency_cache, offsetX, offsetY, 0 ); castLight<1, 0, 0, 1, sight_calc, sight_check>( seen_squares_experiment, transparency_cache, offsetX, offsetY, 0 ); castLight<0, -1, 1, 0, sight_calc, sight_check>( seen_squares_experiment, transparency_cache, offsetX, offsetY, 0 ); castLight<-1, 0, 0, 1, sight_calc, sight_check>( seen_squares_experiment, transparency_cache, offsetX, offsetY, 0 ); castLight<0, 1, -1, 0, sight_calc, sight_check>( seen_squares_experiment, transparency_cache, offsetX, offsetY, 0 ); castLight<1, 0, 0, -1, sight_calc, sight_check>( seen_squares_experiment, transparency_cache, offsetX, offsetY, 0 ); castLight<0, -1, -1, 0, sight_calc, sight_check>( seen_squares_experiment, transparency_cache, offsetX, offsetY, 0 ); castLight<-1, 0, 0, -1, sight_calc, sight_check>( seen_squares_experiment, transparency_cache, offsetX, offsetY, 0 ); } auto end2 = std::chrono::high_resolution_clock::now(); if( iterations > 1 ) { long diff1 = std::chrono::duration_cast<std::chrono::microseconds>(end1 - start1).count(); long diff2 = std::chrono::duration_cast<std::chrono::microseconds>(end2 - start2).count(); printf( "oldCastLight() executed %d times in %ld microseconds.\n", iterations, diff1 ); printf( "castLight() executed %d times in %ld microseconds.\n", iterations, diff2 ); } bool passed = true; map m; for( int x = 0; passed && x < MAPSIZE*SEEX; ++x ) { for( int y = 0; y < MAPSIZE*SEEX; ++y ) { // Check that both agree on the outcome, but not necessarily the same values. if( (seen_squares_control[x][y] > LIGHT_TRANSPARENCY_SOLID) != (seen_squares_experiment[x][y] > LIGHT_TRANSPARENCY_SOLID) ) { passed = false; break; } if( test_bresenham && bresenham_visibility_check(offsetX, offsetY, x, y, transparency_cache) != (seen_squares_experiment[x][y] > LIGHT_TRANSPARENCY_SOLID) ) { passed = false; break; } } } if( !passed ) { for( int x = 0; x < MAPSIZE*SEEX; ++x ) { for( int y = 0; y < MAPSIZE*SEEX; ++y ) { char output = ' '; bool shadowcasting_disagrees = (seen_squares_control[x][y] > LIGHT_TRANSPARENCY_SOLID) != (seen_squares_experiment[x][y] > LIGHT_TRANSPARENCY_SOLID); bool bresenham_disagrees = bresenham_visibility_check( offsetX, offsetY, x, y, transparency_cache ) != (seen_squares_experiment[x][y] > LIGHT_TRANSPARENCY_SOLID); if( shadowcasting_disagrees && bresenham_disagrees ) { if( seen_squares_experiment[x][y] > LIGHT_TRANSPARENCY_SOLID ) { output = 'R'; // Old shadowcasting and bresenham can't see. } else { output = 'N'; // New shadowcasting can't see. } } else if( shadowcasting_disagrees ) { if( seen_squares_control[x][y] > LIGHT_TRANSPARENCY_SOLID ) { output = 'C'; // New shadowcasting & bresenham can't see. } else { output = 'O'; // Old shadowcasting can't see. } } else if( bresenham_disagrees ){ if( seen_squares_experiment[x][y] > LIGHT_TRANSPARENCY_SOLID ) { output = 'B'; // Bresenham can't see it. } else { output = 'S'; // Shadowcasting can't see it. } } if( transparency_cache[x][y] == LIGHT_TRANSPARENCY_SOLID ) { output = '#'; } if( x == offsetX && y == offsetY ) { output = '@'; } printf("%c", output); } printf("\n"); } for( int x = 0; x < MAPSIZE*SEEX; ++x ) { for( int y = 0; y < MAPSIZE*SEEX; ++y ) { char output = ' '; if( transparency_cache[x][y] == LIGHT_TRANSPARENCY_SOLID ) { output = '#'; } else if( seen_squares_control[x][y] > LIGHT_TRANSPARENCY_SOLID ) { output = 'X'; } printf("%c", output); } printf(" "); for( int y = 0; y < MAPSIZE*SEEX; ++y ) { char output = ' '; if( transparency_cache[x][y] == LIGHT_TRANSPARENCY_SOLID ) { output = '#'; } else if( seen_squares_experiment[x][y] > LIGHT_TRANSPARENCY_SOLID ) { output = 'X'; } printf("%c", output); } printf("\n"); } } REQUIRE( passed ); }
void shadowcasting_3d_2d( int iterations ) { // Copy-paste of the above, but for newest FoV vs. the "new" one const unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); std::default_random_engine generator(seed); std::uniform_int_distribution<unsigned int> distribution(0, DENOMINATOR); auto rng = std::bind ( distribution, generator ); float seen_squares_control[MAPSIZE*SEEX][MAPSIZE*SEEY] = {{0}}; float seen_squares_experiment[MAPSIZE*SEEX][MAPSIZE*SEEY] = {{0}}; float transparency_cache[MAPSIZE*SEEX][MAPSIZE*SEEY] = {{0}}; bool floor_cache[MAPSIZE*SEEX][MAPSIZE*SEEY] = {{0}}; // Initialize the transparency value of each square to a random value. for( auto &inner : transparency_cache ) { for( float &square : inner ) { if( rng() < NUMERATOR ) { square = LIGHT_TRANSPARENCY_SOLID; } else { square = LIGHT_TRANSPARENCY_CLEAR; } } } map dummy; const int offsetX = 65; const int offsetY = 65; const int offsetZ = 0; auto start1 = std::chrono::high_resolution_clock::now(); for( int i = 0; i < iterations; i++ ) { // First the control algorithm. castLight<0, 1, 1, 0, sight_calc, sight_check>( seen_squares_control, transparency_cache, offsetX, offsetY, 0 ); castLight<1, 0, 0, 1, sight_calc, sight_check>( seen_squares_control, transparency_cache, offsetX, offsetY, 0 ); castLight<0, -1, 1, 0, sight_calc, sight_check>( seen_squares_control, transparency_cache, offsetX, offsetY, 0 ); castLight<-1, 0, 0, 1, sight_calc, sight_check>( seen_squares_control, transparency_cache, offsetX, offsetY, 0 ); castLight<0, 1, -1, 0, sight_calc, sight_check>( seen_squares_control, transparency_cache, offsetX, offsetY, 0 ); castLight<1, 0, 0, -1, sight_calc, sight_check>( seen_squares_control, transparency_cache, offsetX, offsetY, 0 ); castLight<0, -1, -1, 0, sight_calc, sight_check>( seen_squares_control, transparency_cache, offsetX, offsetY, 0 ); castLight<-1, 0, 0, -1, sight_calc, sight_check>( seen_squares_control, transparency_cache, offsetX, offsetY, 0 ); } auto end1 = std::chrono::high_resolution_clock::now(); const tripoint origin( offsetX, offsetY, offsetZ ); std::array<const float (*)[MAPSIZE*SEEX][MAPSIZE*SEEY], OVERMAP_LAYERS> transparency_caches; std::array<float (*)[MAPSIZE*SEEX][MAPSIZE*SEEY], OVERMAP_LAYERS> seen_caches; std::array<const bool (*)[MAPSIZE*SEEX][MAPSIZE*SEEY], OVERMAP_LAYERS> floor_caches; for( int z = -OVERMAP_DEPTH; z <= OVERMAP_HEIGHT; z++ ) { // TODO: Give some more proper values here transparency_caches[z + OVERMAP_DEPTH] = &transparency_cache; seen_caches[z + OVERMAP_DEPTH] = &seen_squares_experiment; floor_caches[z + OVERMAP_DEPTH] = &floor_cache; } auto start2 = std::chrono::high_resolution_clock::now(); for( int i = 0; i < iterations; i++ ) { // Then the newer algorithm. cast_zlight<0, 1, 0, 1, 0, 0, -1, sight_calc, sight_check>( seen_caches, transparency_caches, floor_caches, origin, 0 ); cast_zlight<1, 0, 0, 0, 1, 0, -1, sight_calc, sight_check>( seen_caches, transparency_caches, floor_caches, origin, 0 ); cast_zlight<0, -1, 0, 1, 0, 0, -1, sight_calc, sight_check>( seen_caches, transparency_caches, floor_caches, origin, 0 ); cast_zlight<-1, 0, 0, 0, 1, 0, -1, sight_calc, sight_check>( seen_caches, transparency_caches, floor_caches, origin, 0 ); cast_zlight<0, 1, 0, -1, 0, 0, -1, sight_calc, sight_check>( seen_caches, transparency_caches, floor_caches, origin, 0 ); cast_zlight<1, 0, 0, 0, -1, 0, -1, sight_calc, sight_check>( seen_caches, transparency_caches, floor_caches, origin, 0 ); cast_zlight<0, -1, 0, -1, 0, 0, -1, sight_calc, sight_check>( seen_caches, transparency_caches, floor_caches, origin, 0 ); cast_zlight<-1, 0, 0, 0, -1, 0, -1, sight_calc, sight_check>( seen_caches, transparency_caches, floor_caches, origin, 0 ); } auto end2 = std::chrono::high_resolution_clock::now(); if( iterations > 1 ) { long diff1 = std::chrono::duration_cast<std::chrono::microseconds>(end1 - start1).count(); long diff2 = std::chrono::duration_cast<std::chrono::microseconds>(end2 - start2).count(); printf( "castLight() executed %d times in %ld microseconds.\n", iterations, diff1 ); printf( "cast_zlight() executed %d times in %ld microseconds.\n", iterations, diff2 ); printf( "new/old execution time ratio: %.02f.\n", (double)diff2 / diff1 ); } bool passed = true; map m; for( int x = 0; passed && x < MAPSIZE*SEEX; ++x ) { for( int y = 0; y < MAPSIZE*SEEX; ++y ) { // Check that both agree on the outcome, but not necessarily the same values. if( (seen_squares_control[x][y] > LIGHT_TRANSPARENCY_SOLID) != (seen_squares_experiment[x][y] > LIGHT_TRANSPARENCY_SOLID) ) { passed = false; break; } } } if( !passed ) { for( int x = 0; x < MAPSIZE*SEEX; ++x ) { for( int y = 0; y < MAPSIZE*SEEX; ++y ) { char output = ' '; bool shadowcasting_disagrees = (seen_squares_control[x][y] > LIGHT_TRANSPARENCY_SOLID) != (seen_squares_experiment[x][y] > LIGHT_TRANSPARENCY_SOLID); bool bresenham_disagrees = bresenham_visibility_check( offsetX, offsetY, x, y, transparency_cache ) != (seen_squares_experiment[x][y] > LIGHT_TRANSPARENCY_SOLID); if( shadowcasting_disagrees && bresenham_disagrees ) { if( seen_squares_experiment[x][y] > LIGHT_TRANSPARENCY_SOLID ) { output = 'R'; // Old shadowcasting and bresenham can't see. } else { output = 'N'; // New shadowcasting can't see. } } else if( shadowcasting_disagrees ) { if( seen_squares_control[x][y] > LIGHT_TRANSPARENCY_SOLID ) { output = 'C'; // New shadowcasting & bresenham can't see. } else { output = 'O'; // Old shadowcasting can't see. } } else if( bresenham_disagrees ){ if( seen_squares_experiment[x][y] > LIGHT_TRANSPARENCY_SOLID ) { output = 'B'; // Bresenham can't see it. } else { output = 'S'; // Shadowcasting can't see it. } } if( transparency_cache[x][y] == LIGHT_TRANSPARENCY_SOLID ) { output = '#'; } if( x == offsetX && y == offsetY ) { output = '@'; } printf("%c", output); } printf("\n"); } for( int x = 0; x < MAPSIZE*SEEX; ++x ) { for( int y = 0; y < MAPSIZE*SEEX; ++y ) { char output = ' '; if( transparency_cache[x][y] == LIGHT_TRANSPARENCY_SOLID ) { output = '#'; } else if( seen_squares_control[x][y] > LIGHT_TRANSPARENCY_SOLID ) { output = 'X'; } printf("%c", output); } printf(" "); for( int y = 0; y < MAPSIZE*SEEX; ++y ) { char output = ' '; if( transparency_cache[x][y] == LIGHT_TRANSPARENCY_SOLID ) { output = '#'; } else if( seen_squares_experiment[x][y] > LIGHT_TRANSPARENCY_SOLID ) { output = 'X'; } printf("%c", output); } printf("\n"); } } REQUIRE( passed ); }